胡牌判断函数
胡牌判断函数
[code]//----------------unt_mainwin.cpp---------------------------------------------------------
/*-----------------------------------------------------------------------------------------
*该函数判断手牌有没有胡牌,手牌的数量一定为[2,5,8,11,14]
*当手牌数量为14时,判断是否有特殊牌型的胡牌[十三么,七对,全不靠]
*当不存在以上牌型时,用递归算法判断是否存在一般的胡牌牌型
*
*作者:yutian(于恬)
*E_main:yution@126.com
*
*作者声明:本代码为学习时编写的代码,大家可以随意转贴及编译修改
*但不得用于商业用途和赌博,作者保留一切权力
*
*鸣谢:网友 shyworm(怕怕虫) E_mail:shyworm@sina.com
* CSDN ChinaUnix
*/
//-----------------------------------------------------------------------------------------------
int TWanJia::IsWin()
{
int i,dblpos,dblcount;
if(this->PaiCount==13) //先处理特殊牌型,七对、十三么及全不靠
{
if((this->PaiInHand[0]==this->PaiInHand[1])&(this->PaiInHand[2]==this->PaiInHand[3])
&(this->PaiInHand[4]==this->PaiInHand[5])&(this->PaiInHand[6]==this->PaiInHand[7])
&(this->PaiInHand[8]==this->PaiInHand[9])&(this->PaiInHand[10]==this->PaiInHand[11])
&(this->PaiInHand[12]==this->PaiInHand[13]))
return SevenDbl; //七对胡了
dblcount=0;
for(i=0;i<13;i++) //以下判断手牌中对子的数量及位置
{
if(this->PaiInHand[i]==this->PaiInHand[i+1])
{
dblcount++;
}
if(dblcount>1) break; //如果手牌中含有两个对子(或一个刻子)以上,只能胡基本牌型
}
if(dblcount==1) //有一个对子的十三张手牌,可能为十三么
{
/***********************************************
十三么牌型必须是么九牌和字牌组成的十四张牌,按牌的数值定义
手牌数组PaiInHand中,只要没有1~7,10~16,19~25这些值,
则可以断定,该数组为十三么
*/
int IsThirteen=1;
for(i=0;i<14;i++)
{
if(this->PaiInHand[i]>0&&this->PaiInHand[i]<8)
{
IsThirteen=0;
break;
}
else if(this->PaiInHand[i]>9&&this->PaiInHand[i]<17)
{
IsThirteen=0;
break;
}
else if(this->PaiInHand[i]>18&&this->PaiInHand[i]<26)
{
IsThirteen=0;
break;
}
}
if(IsThirteen) return ThirteenSmall;
} //end of 十三么
if(dblcount==0)//没有对子,可能是全不靠
{
/*-------------------------------------------
十三不靠牌型为万筒条三个花色的147,258,369加上字牌的七张牌共16张
的任意十四张组成的胡牌,147,258,369的花色可以为任意花色,但不能有两副
出现相同的序数,如一万,四万,一条,四条是不能组成胡牌的。
判定的算法是:
先确定所以序数牌(不是字牌)的个数;
如果序数牌个数大于9,则返回错误;
如果有吃牌的序列(存在两张牌可以吃掉另外一张牌),返回错误;
对于所有的序数牌,自第一个开始,分别与其后的所有牌值mod9得
到的值比较,如果存在相等,返回错误。
如果上面判断都通过,则为十三不靠
*/
int NoWordPos=14;
for(i=13;i>=0;i--)
{
if(this->PaiInHand[i]<=26)
{
NoWordPos=i;
break;
}
}
if(NoWordPos<=8) //如果非字牌有9个以上,肯定不能胡全不靠
{
int IsThirteenSingle=1;
for(i=0;i
{
if((this->PaiInHand[i+1]<=(this->PaiInHand[i]+2))&(this->PaiInHand[i]%9==this->PaiInHand[i+1]%9))
{
IsThirteenSingle=0;
break;
}
}
if(IsThirteenSingle)
{
for(i=0;i
{
for(int j=0;j<=NoWordPos;j++)
{
if(this->PaiInHand[i]==this->PaiInHand[j]%9)
{
IsThirteenSingle=0;
break;
}
}
}
}
if(IsThirteenSingle) return ThirteenSingle;
}
} //end of 不靠
}
int TempPai[33];
for(i=0;i<34;i++) TempPai=0;
for(i=0;i<14;i++)
{
TempPai[this->PaiInHand[i]]++;
}
if(HuPai(TempPai)) return GenaralWin;
return 0;
}
//-----------------------------------------------------------------------------------------------------------------
int TWanJia::HuPai(int * arr)
{
/*
以下代码参考了网友
shyworm(怕怕虫) E_mail:shyworm@sina.com
在csdn论坛发表的算法及源码,在此感谢
原来的算法中要对杠牌进行处理,但我设计的数据结构中,不需要对他们进行判断了,
故略去了一段代码
*/
static int Jiang=0; // 将牌标志,即牌型“三三三三二”中的“二”
if(!RemainPai(arr)) return 1; // 递归退出条件:如果没有剩牌,则和牌返回。
for(int i=1;!arr[i]&i<34;i++); // 找到有牌的地方,i就是当前牌, arr[i]是个数
// 3张组合(刻子)
if(arr[i]>=3) // 如果当前牌不少于3张
{
arr[i]-=3; // 减去3张牌
if(HuPai(arr)) return 1; // 如果剩余的牌组合成功,和牌
arr[i]+=3; // 取消3张组合
}
// 2张组合(将牌)
if(!Jiang&arr[i]>=2) // 如果之前没有将牌,且当前牌不少于2张
{
Jiang=1; // 设置将牌标志
arr[i]-=2; // 减去2张牌
if(HuPai(arr)) return 1; // 如果剩余的牌组合成功,和牌
arr[i]+=2; // 取消2张组合
Jiang=0; // 清除将牌标志
}
if(i>26) return 0; // “东南西北中发白”没有顺牌组合,不和
// 顺牌组合,注意是从前往后组合!
if(i%9!=7&i%9!=8&arr[i+1]&arr[i+2])// 排除数值为8和9的牌且如果后面有连续两张牌
{
arr[i]--;
arr[i+1]--;
arr[i+2]--; // 各牌数减1
if(HuPai(arr)) return 1; // 如果剩余的牌组合成功,和牌
arr[i]++;
arr[i+1]++;
arr[i+2]++; // 恢复各牌数
}
// 无法全部组合,不和!
return 0;
}
//----------------------------------------------------------------------------
// 检查剩余牌数
int TWanJia::RemainPai(int * arr)
{
int sum=0;
for(int i=0;i<34;i++)
sum+=arr[i];
return sum;
}
//----------------------------------------------------------------------------
[/code]
头文件
[code]
//-------------------玩家类及窗体的头文件(修改中)----------------------------------------
#ifndef unt_mainwinH
#define unt_mainwinH
//---------------------------------------------------------------------------
#include
#include
#include
#include
#include
#define SevenDbl 7 //七对
#define ThirteenSmall 13 //十三么
#define ThirteenSingle 14 //十三不靠
#define GenaralWin 15 //一般胡牌
//============================================
// 0 1 2 3 4 5 6 7 8
//============================================
//一万 二万 三万 四万 五万 六万 七万 八万 九万
//============================================
// 9 10 11 12 13 14 15 16 17
//============================================
//一条 二条 三条 四条 五条 六条 七条 八条 九条
//============================================
//18 19 20 21 22 23 24 25 26
//============================================
//一筒 二筒 三筒 四筒 五筒 六筒 七筒 八筒 九筒
//============================================
//27 28 29 30 31 32 33 34 35
//============================================
//东风 南风 西风 北风 红中 发财 白板 花1 花2
//============================================
//---------------------------------------------------------------------------
struct SChiPai //吃牌的结构体,吃的牌为顺子,故记录首尾两张牌
{
int MinPai; //麻将牌值,吃牌中最小的牌
int MaxPai; //麻将牌值,吃牌中最大的牌
};
//---------------------------------------------------------------------------
struct SGangPai //杠牌的结构体
{
int Pai; //麻将牌值,取值范围为[0..33]
int MingAn;//数值为0或1,1代表为暗杠,0代表明杠
};
//---------------------------------------------------------------------------
class TWanJia
{
//__published:
private:
AnsiString PlayerID;
int FenShu; //玩家的分数,要和数据库保持一致
int MenFeng; //玩家的门风
SGangPai Gangpai[3]; //玩家手中杠的牌
SChiPai ChiPai[3]; //玩家手中吃的牌
int PengPai[3]; //玩家手中的碰牌
int HuaPai; //花牌的数量,算番时要用
int PaiInHand[13]; //玩家的手牌,除掉吃碰杠牌后手中的牌
//即其他玩家看不到的牌,最多为十四张
//其中,PaiInHand[13]在处理完成后,被赋值为-1
int PaiCount; //手牌的数量,取值为1,4,7,10,13
int NewPai; //新摸到或别人打的牌,在处理完成后,被赋值为-1
//如果NewPai为非负值,则必须处理掉一张牌或胡牌
protected:
int HuPai(int * arr);
int RemainPai(int * arr);
public:
TWanJia(AnsiString PlayID,int fenzhi);
int SetMenFeng(int menfeng);
int SetFenShu(int fenshu);
int SetGangPai(int pai,int mingan);
int SetChiPai(int min,int max);
int SetPengPai(int pengpai);
int SetPaiInHand(int * paiarr);
int SetPaiCount(int count);
int GetMenFeng();
int GetFenShu();
SGangPai * GetGangPai();
int * GetPengPai();
SChiPai * GetChiPai();
int * GetPaiInHand();
int GetPaiCount();
int Buhua();
int ChiPaiWithTwoPai(int min,int max);
int PengPaiWithOneDbl(int pai);
int IsWin();
int SendThePaiToServer();
int RequireOnePai();
};
//---------------------------------------------------------------------------
class TMJZhuo
{
//__published:
private:
int QuanFen,Header,Tail;
int PaiQiang[143];
TWanJia Players[3];
public:
};
//----------------------------------------------------------------------------
class Tfrm_mainwin : public TForm
{
__published: // IDE-managed Components
TEdit *edt_paiInHand1;
TLabel *Label1;
TEdit *edt_GangPai1;
TLabel *Label2;
TLabel *Label3;
TLabel *Label4;
TEdit *edt_ChiPai11;
TEdit *edt_ChiPai12;
TEdit *edt_ChiPai21;
TEdit *edt_ChiPai22;
TEdit *edt_ChiPai31;
TEdit *edt_ChiPai32;
TEdit *edt_ChiPai41;
TEdit *edt_ChiPai42;
TEdit *edt_GangPai2;
TEdit *edt_GangPai3;
TEdit *edt_GangPai4;
TEdit *edt_GangPai11;
TEdit *edt_GangPai22;
TEdit *edt_GangPai33;
TEdit *edt_GangPai44;
TEdit *edt_PengPai1;
TEdit *edt_PengPai2;
TEdit *edt_PengPai3;
TEdit *edt_PengPai4;
TEdit *edt_paiInHand2;
TEdit *edt_paiInHand3;
TEdit *edt_paiInHand4;
TEdit *edt_paiInHand5;
TEdit *edt_paiInHand6;
TEdit *edt_paiInHand7;
TEdit *edt_paiInHand8;
TEdit *edt_paiInHand9;
TEdit *edt_paiInHand10;
TEdit *edt_paiInHand11;
TEdit *edt_paiInHand12;
TEdit *edt_paiInHand13;
TEdit *edt_paiInHand14;
TBitBtn *btn_IsWin;
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
void __fastcall btn_IsWinClick(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
private: // User declarations
TWanJia * Player;
public: // User declarations
void SendDataToWanJia();
void DispWanJiaData();
__fastcall Tfrm_mainwin(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE Tfrm_mainwin *frm_mainwin;
//---------------------------------------------------------------------------
#endif
[/code]