Bootstrap

扑克类游戏斗地主、蜘蛛纸牌源码

11号,硬着头皮吃水饺,不知道馅是什么肉做的,应该没有三会火腿肠好吧.....

这是移植自网上搜索到的两个扑克类游戏,原游戏是MFC做的,移植到了OpenGL中。两者的渲染方式不同,架构有所改变。总共没花几天时间,如果自己从头写估计至少要用几个月。

扑克类游戏主要是数据结构要列好,算法都是初级的入门算法,繁琐但是并不困难。

继续给游戏添加了联机和自动出牌功能,出牌智商有点弱。

抽象出一些基类PokerGame,PokerPlayer方便派生出多种类型的游戏。斗地主游戏PokerDouDiZhu或其它的出牌类游戏比如‘’红心大战‘’都可以继承自PokerGame类。斗地主玩家基类DouDizhuPlayer也继承自PokerPlayer。

还是原先的小游戏架构分三种类型的玩家: (Player、Robot、Role) 

DouDizhuPlayer             继承自PokerPlayer是斗地主玩家基类,只有被动出牌功能(只响应出牌消息,不主动发送出牌消息给主机和其它玩家)。

DouDizhuPlayerRobot   继承自DouDizhuPlayer是AI玩家类,具有自动出牌功能(主动发送出牌消息)。

DouDizhuPlayerRole     继承自DouDizhuPlayerRobot是实体玩家类,具有自动出牌功能的同时也可以手选出牌。

对于蜘蛛纸牌游戏,结构上和斗地主类出牌的游戏应该算是两种不同的类型了。这个蜘蛛纸牌游戏只加了提示出牌功能,没有做联机和自动出牌。

定义纸牌ID:

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerGame.h
//  @Brief:     PokerGame
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#if !defined(PokerCard_h__)
#define PokerCard_h__

//扑克牌ID
enum CardID
{
	MEIH2=0,
	MEIH3,
	MEIH4,
	MEIH5,
	MEIH6,
	MEIH7,
	MEIH8,
	MEIH9,
	MEIH10,
	MEIHJ,
	MEIHQ,
	MEIHK,
	MEIHA,
	FANGK2,  
	FANGK3,  
	FANGK4,  
	FANGK5,  
	FANGK6,  
	FANGK7,  
	FANGK8,  
	FANGK9,  
	FANGK10, 
	FANGKJ,  
	FANGKQ,  
	FANGKK,  
	FANGKA,  
	HEIT2,
	HEIT3,
	HEIT4,
	HEIT5,
	HEIT6,
	HEIT7,
	HEIT8,
	HEIT9,
	HEIT10,  
	HEITJ,
	HEITQ,
	HEITK,
	HEITA,
	HONGT2,  
	HONGT3,  
	HONGT4,  
	HONGT5,  
	HONGT6,  
	HONGT7,  
	HONGT8,  
	HONGT9,  
	HONGT10, 
	HONGTJ,  
	HONGTQ,  
	HONGTK,  
	HONGTA,  
	JokerSmall,      
	JokerBig,
	CardNum
};


//单张牌
class Card
{
public:	
	Card();
	int  Color();           //牌的花色

	bool   bClicked;	    //是否被左键选中待出牌
	int    cardValue;		//牌面值
	CardID cardID;	
};

#endif 

出牌型游戏基类:

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerGame.h
//  @Brief:     PokerGame
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#if !defined(PokerGame_h__)
#define PokerGame_h__

#include "Render/Texture.h"
#include "Poker/PokerCard.h"
#include "Rpg/MiniGame.h"

#define MaxPlayerCard		20  //玩家最多持牌数
#define RenderShiftX		20  //牌之间距离
#define RenderShiftY		20

#define RenderLeftRightSpace	10  //牌距离屏幕左右留空
#define RenderUpDownSpace	    10   //牌距离屏幕上下留空
#define RenderUpDownDistance	25   //上下第二排牌距离第一排留空
#define RenderClickedAddDistance	20 //点选后牌高出的长度

#define Board2DCen (G_PokerGame->BoardRect2D.GetCen())

//显示座位:不同的客户端看到的不一样(不是每个客户端都是坐北朝南)
enum ChairPostion
{
	SP_Down,
	SP_Right,
	SP_Up,
	SP_Left,
};

//网络消息
enum MiniPokerCmd
{
	CMD_ShuffleCard,  //洗牌
	CMD_BeLord     ,  //叫地主
	CMD_NotBeLord  ,  //不叫地主
	CMD_OutCard    ,  //出牌
	CMD_Pass       ,  //过
	CMD_GameOver   ,  //结束
	CMD_Restart    ,  //重新开始
};
const char* PokerCmdToString(int enumeration);

class SoundChannel;
class GuiMovieCtrl;
class PokerGame;
//玩家的数据结构
class PokerPlayer:public MiniPlayer
{
public:
	PokerPlayer();
	virtual~PokerPlayer();
	virtual bool Start();
	virtual bool Stop();
	virtual void Update();
	virtual void Render();

	virtual void RecvCard(CardID cardID);
	virtual void SortCard();   //整牌

	//出牌
	virtual void OutCard();	

	//张数
	int CountCard(int value);
	//
	int MinCard(int temp[], int num);
	//分析牌 各value值的张数
	void AnalyseCard();

	bool ClickCards(int cardValue[],int num);		//改变牌状态,标记待出
	bool ClickCardsID(int cardID[],int num);		//改变牌状态,标记待出
	int  ClickCard(const vec2& pos);

	ChairPostion  m_screenPos;			//显示座位:上下左右
	bool m_workingWithAI;		

	Card m_cards[MaxPlayerCard];	
	int	 m_cardNum;				
	int  m_turn;                        //统一座位:东西南北

	int  m_outNum;		        //出到桌面的牌数
	bool m_notOut;				//不出牌的标记
	int  ValueCount[18];	    //各value值的张数

	int  m_totalScore;			//记录总分
	int  m_turnScore;			//记录这回合得分

	int CardY;					//south myplayer第一张牌左上角 xy
	int CardX;					 
	int m_clickedNum;			//点击待出的牌数

	bool  m_bBaoPai;

	PokerGame*  m_game;

	SoundChannel*  m_sound;
	GuiMovieCtrl*  m_movieCtrl;
};

//准备要出的牌
class ToOutCards
{
public:
	ToOutCards();
	Card m_cards[MaxPlayerCard];	
	int	 m_cardNum;	
	//张数
	int CountCard(int value);
	//最小的牌
	int MinCard();
};

//游戏状态
enum PokerGameStatus
{
	Waiting,  //准备
	Dealing,  //发牌
	Preparing,//叫地主中
	Playing,  //进行中
	Resulting,//显示结果
};

//牌的状态
enum CardFlag
{
	NotDeal = 0,//未发的牌
	InHand,     //已发牌未出的牌
	BeOut,      //已出的牌
};

class PacketBase;
class PokerGame
{
public:
	PokerGame();
	virtual ~PokerGame();

	virtual bool Start();
	virtual bool Stop();
	virtual bool Render();
	virtual bool Update();
	virtual bool Free();
	
	virtual bool CheckRoundEnd();				//回合结束判断
	virtual void FirstOut();					//游戏开始首次出牌	

	virtual void StateDealCard();				//发牌
	virtual void SignCard(Card *card);		//标记牌分值
	virtual void NextTurn();

	void ShuffleCard();        //洗牌
	virtual void OutCard(PokerPlayer*player);	//出牌

	PokerPlayer* GetTurnPlayer();		

	//处理游戏网络命令包
	virtual int  ProcessPacketCmd(PacketBase* packet);
	//virtual const char* CmdToString(const char* stream,int len);


	PokerGameStatus m_gameStatus;
	CardFlag m_cardFlag[CardNum];		//出牌标记
	/*CardID*/char   m_cardShuffle[CardNum];    //洗牌结果
	PokerPlayer*  m_players[4];			
	PokerPlayer*  m_myPlayer;
	int  m_playerNum;				
	int  m_turn;				//出牌位置
	int  m_lastOutTurn;		    //上次出牌位置
	float m_turnTime;           //换手时间

	int   m_dealCardNum;
	float m_dealAccumTime;
					
	int CardHeight;				//牌长
	int CardWidth;				//牌宽

	bool m_openPoker;

	bool m_bHost;

	TexturePtr m_texBack;
	TexturePtr m_cardTexture[CardNum];
	TexturePtr m_cardBackTexture;
	TexturePtr m_thinkTexture[4];
	TexturePtr m_passTexture[4];
	TexturePtr m_passButtonTexture;
};

#endif 

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerGame.cpp
//  @Brief:     PokerGame
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#include "General/Pch.h"
#include "General/Window.h"
#include "General/Timer.h"
#include "Poker/PokerGame.h"
#include "Render/RendDriver.h"
#include "Render/Texture.h"
#include "Render/Font.h"
#include "Packet/PacketMiniGame.h"
#include "Sound/ChannelSound.h"
#include "Rpg/MiniGame.h"
#include <stdlib.h>
#include "General/Pce.h"
#include "MiniGamePoker.h"
#include "Rpg/SyncGameInfo.h"


PokerGame::PokerGame()
{
	m_gameStatus = Dealing;
	m_openPoker = false;
	for (int i=0;i<4;i++)
	{
		 m_players[i] = NULL;
	}
}

PokerGame::~PokerGame()
{
	Free();
}

void PokerGame::StateDealCard()
{
}


void PokerGame::OutCard(PokerPlayer*player)
{
	G_PokerGame->PlaySound__("data/sound/step_foot.wav");
	for(int i = 0; i < player->m_cardNum; i++)
	{
		if(player->m_cards[i].bClicked == true)
		{
			m_cardFlag[player->m_cards[i].cardID] = BeOut;
		}
	}
	player->OutCard();
}

void PokerGame::FirstOut()
{
}



bool PokerGame::CheckRoundEnd()
{
	return false;
}

bool PokerGame::Render()
{
	G_RendDriver->Color4f(1,1,1,1);
	G_RendDriver->SetRenderStateEnable(RS_BLEND,true);
	G_RendDriver->BlendFunc(Blend_Filter);

	//if(m_gameStatus == Playing)
	{
		for(int i = 0; i < m_playerNum; i++)
		{
			m_players[i]->Render();
		}
	}
	return true;
}

bool PokerGame::Start()
{  
	m_gameStatus = Dealing;
	m_dealCardNum = 0;
	m_dealAccumTime = 0;
	m_turn = 0;
	m_lastOutTurn = -1;

	for(int i = 0; i < CardNum; i++)
		m_cardFlag[i] = NotDeal;

	G_TextureMgr->AddTexture(m_texBack, "data/minigame/poker/back.png");

	const char* cardTexName[] = 
	{
		"data/minigame/poker/mei2.png",
		"data/minigame/poker/mei3.png",
		"data/minigame/poker/mei4.png",
		"data/minigame/poker/mei5.png",
		"data/minigame/poker/mei6.png",
		"data/minigame/poker/mei7.png",
		"data/minigame/poker/mei8.png",
		"data/minigame/poker/mei9.png",
		"data/minigame/poker/mei10.png",
		"data/minigame/poker/meiJ.png",
		"data/minigame/poker/meiQ.png",
		"data/minigame/poker/meiK.png",
		"data/minigame/poker/meiA.png",

		"data/minigame/poker/fang2.png",
		"data/minigame/poker/fang3.png",
		"data/minigame/poker/fang4.png",
		"data/minigame/poker/fang5.png",
		"data/minigame/poker/fang6.png",
		"data/minigame/poker/fang7.png",
		"data/minigame/poker/fang8.png",
		"data/minigame/poker/fang9.png",
		"data/minigame/poker/fang10.png",
		"data/minigame/poker/fangJ.png",
		"data/minigame/poker/fangQ.png",
		"data/minigame/poker/fangK.png",
		"data/minigame/poker/fangA.png",

		"data/minigame/poker/hei2.png",
		"data/minigame/poker/hei3.png",
		"data/minigame/poker/hei4.png",
		"data/minigame/poker/hei5.png",
		"data/minigame/poker/hei6.png",
		"data/minigame/poker/hei7.png",
		"data/minigame/poker/hei8.png",
		"data/minigame/poker/hei9.png",
		"data/minigame/poker/hei10.png",
		"data/minigame/poker/heiJ.png",
		"data/minigame/poker/heiQ.png",
		"data/minigame/poker/heiK.png",
		"data/minigame/poker/heiA.png",

		"data/minigame/poker/hong2.png",
		"data/minigame/poker/hong3.png",
		"data/minigame/poker/hong4.png",
		"data/minigame/poker/hong5.png",
		"data/minigame/poker/hong6.png",
		"data/minigame/poker/hong7.png",
		"data/minigame/poker/hong8.png",
		"data/minigame/poker/hong9.png",
		"data/minigame/poker/hong10.png",
		"data/minigame/poker/hongJ.png",
		"data/minigame/poker/hongQ.png",
		"data/minigame/poker/hongK.png",
		"data/minigame/poker/hongA.png",

		"data/minigame/poker/xiaowang.png",
		"data/minigame/poker/dawang.png",
	};
	for (int i=0;i<CardNum;i++)
	{
		G_TextureMgr->AddTexture(m_cardTexture[i],cardTexName[i]);
	}
	G_TextureMgr->AddTexture(m_cardBackTexture,"data/minigame/poker/cardback01.png");
	G_TextureMgr->AddTexture(m_passTexture[0],"data/minigame/poker/donotout00.png");
	G_TextureMgr->AddTexture(m_passTexture[1],"data/minigame/poker/donotout01.png");
	G_TextureMgr->AddTexture(m_passTexture[2],"data/minigame/poker/donotout02.png");
	G_TextureMgr->AddTexture(m_passTexture[3],"data/minigame/poker/donotout03.png");

	G_TextureMgr->AddTexture(m_thinkTexture[0],"data/minigame/poker/think00.png");
	G_TextureMgr->AddTexture(m_thinkTexture[1],"data/minigame/poker/think01.png");
	G_TextureMgr->AddTexture(m_thinkTexture[2],"data/minigame/poker/think02.png");
	G_TextureMgr->AddTexture(m_thinkTexture[3],"data/minigame/poker/think03.png");
	G_TextureMgr->AddTexture(m_passButtonTexture,"data/minigame/poker/donotoutbutton.png");

	CardHeight = 96;
	CardWidth = 71;
	
	if (m_bHost)
	{
		ShuffleCard();
		C2SPacketMiniGameCmd packet;
		packet.WriteHeader();
		packet.WriteValue(CMD_ShuffleCard);  //todo每个人只发各自的牌,地主牌叫过另发。防止外挂作弊。
		packet.WriteValue(m_cardShuffle);    //seed即可
		G_MiniGame->SendPacketToOther(&packet);
	}
	else
	{
		for (int i = 0; i < CardNum; i++)
		{
			m_cardShuffle[i] = -1;
		}
	}
	return true;
}
bool PokerGame::Stop()
{  
	Free();
	return true;
}
PokerPlayer* PokerGame::GetTurnPlayer()
{
	return m_players[m_turn];
}

void PokerGame::SignCard(Card *card)
{

}

bool PokerGame::Update()
{
	m_turnTime += G_Timer->GetStepTimeLimited();
	if (m_gameStatus == Preparing
		||m_gameStatus == Playing)
	{
		GetTurnPlayer()->Update();
	}
	return true;
}

bool PokerGame::Free()
{
	for (int i=0;i<4;i++)
	{
		SafeDelete(m_players[i]);
	}
	return true;
}

void PokerGame::NextTurn()
{
	int nextTurn = (++m_turn) % m_playerNum;
	m_turn = nextTurn;
	m_players[nextTurn]->m_outNum = 0;
	m_players[nextTurn]->m_notOut = 0;

	//m_players[(1+m_turn) % m_playerNum]->m_notOut = 0;
	m_turnTime = 0;
}

void PokerGame::ShuffleCard() //洗牌
{
	for (int i = 0; i < CardNum; i++)
	{
		m_cardShuffle[i] = (CardID)i;
	}
	// 随机i-1中的任意一个数与i交换
	for (int i = 2; i < CardNum; i++)
	{
		int ran = Rand()%i;
		char temp = m_cardShuffle[ran];
		m_cardShuffle[ran] = m_cardShuffle[i];
		m_cardShuffle[i] = temp;
	}
}

int  PokerGame::ProcessPacketCmd(PacketBase* packet)
{
	int cmd;
	packet->ReadValue(cmd);
	switch(cmd)
	{
	case CMD_ShuffleCard:
		{
			//todo 只发自己的牌
			packet->ReadValue(m_cardShuffle);
		}
		return 1;
	}

	return 0;
}



Card::Card()
{
	bClicked = false;
}

int Card::Color()
{
	if(cardID == JokerSmall)
	{
		return 4; //小王 黑桃&&梅花
	}
	else if(cardID == JokerBig)
	{
		return 5;
	}
	else if(cardID >= 0 && cardID < JokerSmall)
	{
		return cardID / 13;
	}
	return 0;
}


PokerPlayer::PokerPlayer()
:m_workingWithAI(false)
,m_clickedNum(0)
,m_movieCtrl(NULL)
{
	m_sound = new SoundChannel;
}

PokerPlayer::~PokerPlayer()
{
	SafeDelete(m_sound);
}

void PokerPlayer::AnalyseCard()
{
	for(int i = 0; i < 18; i++)
	{
		ValueCount[i] = CountCard(i);
	}
}

int  PokerPlayer::MinCard(int temp[], int num)
{
	int i, min = temp[0];
	for(i = 1; i < num; i++)
	{
		if(temp[i] < min)
		{
			min = temp[i];
		}
	}
	return min;
}

int  PokerPlayer::CountCard(int value)
{
	int n = 0; 
	for(int i = 0 ; i < m_cardNum ; i++)
	{
		if(m_cards[i].cardValue == value)
			n++;
	}
	return n;
}

void PokerPlayer::RecvCard(CardID cardID)
{
	m_cards[m_cardNum].cardID = cardID;
	m_cards[m_cardNum].bClicked = false;
	m_game->SignCard(&m_cards[m_cardNum]);
	m_cardNum++;

	m_sound->PlaySound__("data/sound/chess_duk.wav");
}

bool PokerPlayer::Start()
{
	for(int j = 0; j < MaxPlayerCard; j++)
	{
		m_cards[j].cardID = (CardID)0;
		m_cards[j].cardValue = -1;
		m_cards[j].bClicked = false;
	}
	m_cardNum = 0;
	m_outNum = 0;
	m_screenPos = SP_Up;
	m_totalScore = 0;
	m_turnScore = 0;
	m_bBaoPai = false;
	return true;
}

bool PokerPlayer::Stop()
{
	Free();
	return true;
}

void PokerPlayer::OutCard()
{
	Card card;
	int outNum = 0;
	int i = 0;
	while(i < m_cardNum)
	{
		if(m_cards[i].bClicked == true)
		{
			card = m_cards[i];

			//把被选中的牌挪到最后(显示出牌用),后面依次前移
			for(int j = i; j < MaxPlayerCard; j++)
				m_cards[j] = m_cards[j+1];

			card.bClicked = false;

			m_cards[MaxPlayerCard - 1] = card;
			m_cardNum--;
			outNum++;
		}
		else
			i++;
	}
	m_outNum = outNum;
	m_clickedNum = 0;
}

void PokerPlayer::SortCard()
{

}

void PokerPlayer::Update()
{

}

void PokerPlayer::Render()
{
	int CardHeight=m_game->CardHeight;				
	int CardWidth=m_game->CardWidth;	

	///显示名字
	if (GetPlayerInfo())
	{
		if(m_screenPos == SP_Down)
		{
			G_FontMgr->TextAtPos(vec2(Board2DCen.x - 33,  G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace), GetPlayerInfo()->playerName);
		}
		else if(m_screenPos == SP_Up)
		{
			G_FontMgr->TextAtPos(vec2(Board2DCen.x - 33,  G_PokerGame->BoardRect2D.y+RenderUpDownSpace), GetPlayerInfo()->playerName);
		}
		else if(m_screenPos == SP_Right)
		{
			G_FontMgr->TextAtPos(vec2(G_Window->m_iWidth - 66 - 5, Board2DCen.y), GetPlayerInfo()->playerName);
		}
		else if(m_screenPos == SP_Left)
		{
			G_FontMgr->TextAtPos(vec2(5, Board2DCen.y), GetPlayerInfo()->playerName);
		}
	}

	G_RendDriver->Color3f(1,1,1);
	///显示未出的牌
	bool canSee = m_game->m_openPoker;//明牌
	switch(m_screenPos)
	{
	case SP_Down:
		{
			CardX = Board2DCen.x - ((m_cardNum - 1) * RenderShiftX + CardWidth)/2;
			CardY = G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace - CardHeight;
			for(int i = 0; i < m_cardNum; i++)
			{
				if(m_cards[i].bClicked == false)
				{
					m_game->m_cardTexture[m_cards[i].cardID]->Bind();
					G_RendDriver->DrawTextureRect(RectF(CardX+i* RenderShiftX, CardY, CardWidth, CardHeight));
				}
				else
				{
					m_game->m_cardTexture[m_cards[i].cardID]->Bind();
					G_RendDriver->DrawTextureRect(RectF(CardX+i * RenderShiftX, CardY -RenderClickedAddDistance, CardWidth, CardHeight));
				}
			}
		}
		break;

	case SP_Right:
		{
			int x = G_PokerGame->BoardRect2D.GetRight() - RenderLeftRightSpace- CardWidth;
			int y = Board2DCen.y - (m_cardNum * RenderShiftY + CardHeight)/2;
			for(int i = 0; i < m_cardNum; i++)
			{
				if (canSee) 
					m_game->m_cardTexture[m_cards[i].cardID]->Bind();
				else
					m_game->m_cardBackTexture->Bind();
				G_RendDriver->DrawTextureRect(RectF(x, y + i * RenderShiftY, CardWidth, CardHeight));
			}
		}
		break;
	case SP_Up:
		{
			int x = Board2DCen.x - ((m_cardNum - 1) * RenderShiftX + CardWidth)/2; 
			int y = G_PokerGame->BoardRect2D.y + RenderUpDownSpace;
			for(int i = 0; i < m_cardNum; i++)
			{
				if (canSee) 
					m_game->m_cardTexture[m_cards[i].cardID]->Bind();
				else
					m_game->m_cardBackTexture->Bind();
				G_RendDriver->DrawTextureRect(RectF(x + i * RenderShiftX, y, CardWidth, CardHeight));
			}
		}
		break;
	case SP_Left:
		{
			int x = G_PokerGame->BoardRect2D.x + RenderLeftRightSpace;
			int y = Board2DCen.y - (m_cardNum * RenderShiftY + CardHeight)/2;
			for(int i = 0; i < m_cardNum; i++)
			{
				if (canSee) 
					m_game->m_cardTexture[m_cards[i].cardID]->Bind();
				else
					m_game->m_cardBackTexture->Bind();
				G_RendDriver->DrawTextureRect(RectF(x, y + i * RenderShiftY, CardWidth, CardHeight));
			}
		}
		break;
	}
	

	显示所出的牌
	{
		int outX, outY;
		int i, j;
		if(m_screenPos == SP_Down)
		{
			outX = Board2DCen.x - m_outNum * RenderShiftX/2 - RenderShiftX;
			outY = G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace - CardHeight * 2 - RenderUpDownDistance;
			for(i = MaxPlayerCard - m_outNum, j=0; i < MaxPlayerCard; i++, j++)
			{
				m_game->m_cardTexture[m_cards[i].cardID]->Bind();
				G_RendDriver->DrawTextureRect(RectF( outX+j * RenderShiftX, outY, CardWidth,CardHeight));
			}
		}
		if(m_screenPos == SP_Right)
		{
			outX = G_PokerGame->BoardRect2D.GetRight() - RenderLeftRightSpace - CardWidth*2.8f; 
			outY = Board2DCen.y - ((m_outNum - 1) * RenderShiftY + CardHeight)/2;
			for(i = MaxPlayerCard - m_outNum, j = 0; i < MaxPlayerCard; i++, j++)
			{
				m_game->m_cardTexture[m_cards[i].cardID]->Bind();
				G_RendDriver->DrawTextureRect(RectF(outX, outY+j * RenderShiftY, CardWidth,CardHeight ));
			}
		}
		if(m_screenPos == SP_Up)
		{
			outX = Board2DCen.x - ((m_outNum - 1) * RenderShiftX + CardWidth)/2;
			outY = G_PokerGame->BoardRect2D.y + RenderUpDownSpace + CardHeight + RenderUpDownDistance;
			for(i = MaxPlayerCard - m_outNum, j=0; i < MaxPlayerCard; i++, j++)
			{
				m_game->m_cardTexture[m_cards[i].cardID]->Bind();
				G_RendDriver->DrawTextureRect(RectF( outX+j * RenderShiftX, outY , CardWidth,CardHeight ));
			}
		}
		if(m_screenPos == SP_Left)
		{
			outX = G_PokerGame->BoardRect2D.x + RenderLeftRightSpace + CardWidth*1.8f; 
			outY = Board2DCen.y - ((m_outNum - 1) * RenderShiftY + CardHeight)/2;
			for(i = MaxPlayerCard - m_outNum, j = 0; i < MaxPlayerCard; i++, j++)
			{
				m_game->m_cardTexture[m_cards[i].cardID]->Bind();
				G_RendDriver->DrawTextureRect(RectF(outX, outY+j * RenderShiftY, CardWidth,CardHeight));
			}
		}
	}
}
//标记要出牌
bool PokerPlayer::ClickCards(int cardValue[],int num)
{
	int find = 0;
	for(int i = 0; i < num; i++)
	{
		for(int j = 0; j < m_cardNum; j++)
		{
			if(m_cards[j].cardValue == cardValue[i] 
			&& m_cards[j].bClicked == false //有可能两张相同value
				)
			{
				find++;
				m_cards[j].bClicked = true;
				break;
			}
		}
	}
	assert(find == num);
	return (find == num);
}
//标记要出牌
bool PokerPlayer::ClickCardsID(int cardID[],int num)
{
	int find = 0;
	for(int i = 0; i < num; i++)
	{
		for(int j = 0; j < m_cardNum; j++)
		{
			if(m_cards[j].cardID == cardID[i] 
			&& m_cards[j].bClicked == false //有可能两张相同value
				)
			{
				find++;
				m_cards[j].bClicked = true;
				break;
			}
		}
	}
	assert(find == num);
	return (find == num);
}

int  PokerPlayer::ClickCard(const vec2& mousePos)
{
	int x1, y1, x2, y2;
	x1 = CardX;
	y1 = CardY - RenderClickedAddDistance;
	x2 = (m_cardNum - 1) * RenderShiftX + m_game->CardWidth + CardX;
	y2 = CardY + m_game->CardHeight;

	if((mousePos.x < x2) && (mousePos.x > x1) 
		&& (mousePos.y > y1) && (mousePos.y < y2))
	{
		if(m_cardNum != 0)
		{	
			int n;
			n = (mousePos.x - CardX) / RenderShiftX;
			if(n >= m_cardNum)
				n = m_cardNum - 1;
			if(m_cards[n].bClicked == false)
			{
				m_cards[n].bClicked = true;
				m_clickedNum++;
			}
			else if(m_cards[n].bClicked == true)
			{
				m_cards[n].bClicked = false;
				m_clickedNum--;
			}
			m_sound->PlaySound__("data/sound/chess_duk.wav");
		}
	}
	return 0;
}


ToOutCards::ToOutCards()
{
	for(int i = 0; i < MaxPlayerCard; i++)
	{
		m_cards[i].cardID = (CardID)0;
		m_cards[i].cardValue = -1;
	}
	m_cardNum = 0;
}

int  ToOutCards::MinCard()
{
	int min = m_cards[0].cardValue;
	for(int i = 1; i < m_cardNum; i++)
	{
		if(m_cards[i].cardValue < min)
		{
			min = m_cards[i].cardValue;
		}
	}
	return min;
}

int  ToOutCards::CountCard(int value)
{
	int n = 0; 
	for(int i = 0 ; i < m_cardNum ; i++)
		if(m_cards[i].cardValue == value)
			n++;
	return n;
}

const char* PokerCmdToString(int enumeration)
{
	switch(enumeration)
	{
	case CMD_ShuffleCard:return "CMD_ShuffleCard";		
	case CMD_BeLord     :return "CMD_BeLord     ";		
	case CMD_NotBeLord  :return "CMD_NotBeLord  ";		
	case CMD_OutCard    :return "CMD_OutCard    ";		
	case CMD_Pass       :return "CMD_Pass       ";	
	case CMD_GameOver   :return "CMD_GameOver   ";		
	case CMD_Restart    :return "CMD_Restart    ";		
	default             :return "CMD_unknow";
	}
	return "CMD_unknow";
}

斗地主游戏派生类:

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerDouDiZhu.h
//  @Brief:     PokerDouDiZhu
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#if !defined(DouDiZhu_h__)
#define DouDiZhu_h__

#include "PokerGame.h"

//准备要出的牌
class ToOutCardsDouDizhu:public ToOutCards
{
public:
						
};

enum OutType
{
	None = -1,
	GZ = 0, //单张
	DZ    , //对子
	SZ    , //顺子
	SGBD  , //三张不带
	SD1   , //三带一
	SD2   , //三带二
	SD2G  , //四带二
	SD2D  , //四带二对
	LD3   , //三连对
	LD4   ,
	LD5   ,
	LD6   ,
	LD7   ,
	FJBD  , //飞机不带
	FJD2G , //飞机带二个
	FJD2D , //飞机带两对
	SFJBD , //三飞机不带
	SFJDSG, //三飞机带三个
	SFJDSD, //三飞机带三对
	ZD    , //炸弹
	SW    , //双王
};
struct CurOutCards
{
	int  value;
	OutType type;
	//char type[10];
	int  num;
	int  min;
};
class DouDizhuPlayerRobot;
class DouDizhuPlayerRole;

class PokerDouDiZhu:public PokerGame
{
public:
	enum CardValue
	{
		Value3 = 3,
		Value4,
		Value5,
		Value6,
		Value7,
		Value8,
		Value9,
		Value10,
		ValueJ,
		ValueQ,
		ValueK,
		ValueA = 14,
		Value2 = 15,
		ValueJokerSmall = 16,      
		ValueJokerBig = 17,
	};
	PokerDouDiZhu();
	virtual ~PokerDouDiZhu();

	virtual bool Start();
	virtual bool Stop();
	virtual bool Render();
	virtual bool Update();
	virtual bool CheckRoundEnd();				//结束判断

	virtual void StateDealCard();			    //发牌
	void StateDecideLord();	                    //选地主

	//注意:不要循环发送,比如主机发过来,调用了几层函数又发回去
	void SendDecideLord(int turn);                  //
	void DecideLord(int turn);                  //选出地主

	virtual void SignCard(Card *card);		    //标记牌分值

	virtual void FirstOut();					//首次出牌		

	//没出的最大单牌
	int MaxCard();							

	void OnRButtonDown();

	bool Button_NotBeLord();
	bool Button_BeLord();
	bool Button_Pass();

	//处理游戏网络命令包
	virtual int  ProcessPacketCmd(PacketBase* packet);
	//virtual const char* CmdToString(const char* stream,int len);


	int  m_winnerTurn;				//标记哪个是赢家
	int  m_lordTurn;			    //地主位置
	Card m_lordCard[3];			    //三张地主牌


	CurOutCards         m_curOutCards;
	ToOutCardsDouDizhu  m_toOutCards;		//准备要出的牌
	
	DouDizhuPlayerRole* m_myRolePlayer;	

	TexturePtr m_lordTexture;
	TexturePtr m_notbeLordTexture;
	TexturePtr m_notbeLordButtonTexture;
	TexturePtr m_sanfenButtonTexture;

	TexturePtr m_winTexture;
	TexturePtr m_loseTexture;

	//炸弹倍数
	int m_zhadanNum;


};
extern PokerDouDiZhu* G_PokerDouDiZhu;

#endif

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerDouDiZhu.cpp
//  @Brief:     PokerDouDiZhu
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================

#include "General/Pch.h"
#include "General/Timer.h"
#include "General/Window.h"
#include "Input/InputMgr.h"
#include "Poker/PokerDoudizhu.h"
#include "Poker/PokerGame.h"
#include "Poker/DouDiZhuPlayer.h"
#include "Poker/MiniGamePoker.h"
#include "Poker/MiPoker_PlayGui.h"
#include "Net/PacketList.h"
#include "Gui/MiniGuis.h"
#include "Gui/GuiMgr.h"
#include "Gui/GuiControlMisc.h"
#include "Rpg/MiniGame.h"
#include "Rpg/SyncGameInfo.h"
#include "Packet/PacketMiniGame.h"
#include "Render/RendDriver.h"
#include "Render/Texture.h"
#include "Sound/ChannelSound.h"
#include "General/Pce.h"

PokerDouDiZhu* G_PokerDouDiZhu = NULL;

PokerDouDiZhu::PokerDouDiZhu()
{
	m_lastOutTurn = -1;
	m_lordTurn = -1;
	m_winnerTurn = -1;
	G_PokerDouDiZhu = this;

}

PokerDouDiZhu::~PokerDouDiZhu()
{

}

bool PokerDouDiZhu::Start()
{
	m_myRolePlayer = NULL;//?
	PokerGame::Start();

	G_TextureMgr->AddTexture(m_notbeLordTexture,"data/minigame/poker/bujiao.png");
	G_TextureMgr->AddTexture(m_notbeLordButtonTexture,"data/minigame/poker/bujiaobutton.png");
	G_TextureMgr->AddTexture(m_lordTexture,"data/minigame/poker/islord.png");
	G_TextureMgr->AddTexture(m_sanfenButtonTexture,"data/minigame/poker/sanfen.png");
	G_TextureMgr->AddTexture(m_winTexture,"data/minigame/poker/win.png");
	G_TextureMgr->AddTexture(m_loseTexture,"data/minigame/poker/lose.png");

	m_turnTime = 0;
	m_lordTurn = -1;
	m_myPlayer = NULL;
	
	//
	m_playerNum = 3;
	for(int i = 0; i < m_playerNum; i++)
	{
		MyRoomPlayerInfo* playerInfo = G_SyncMyRoomInfo->GetPlayerFromIndex(i);

		if (playerInfo)
		{
			//roomSlot 不一定连续,但已经排序
			if (playerInfo->roomSlot == G_SyncMyRoomInfo->m_myRoomSlot)
			{
				m_players[i] = m_myRolePlayer = new DouDizhuPlayerRole;
				m_myPlayer = m_myRolePlayer;
			}
			else
			{
				if (G_PokerGame->IsHost()==false ||
					playerInfo->isAI==false)
				{
					//非主机上ai表现同实体玩家
					m_players[i] = new DouDizhuPlayer;
				}
				else
				{
					//主机负责ai玩家的模拟
					m_players[i] = new DouDizhuPlayerRobot;
				}
			}
			m_players[i]->SetPlayerInfo(playerInfo);
		}
		else
		{
			return false;
		}
	}

	//
	if (m_myRolePlayer)
	{
		m_myRolePlayer->m_toOutCard = &m_toOutCards;
	}
	else
	{
		return false;
	}
	for(int i = 0; i < m_playerNum; i++)
	{
		dynamic_cast<DouDizhuPlayer*>(m_players[i])->g_curOutCards = &m_curOutCards;
		m_players[i]->m_turn = i;
		m_players[i]->m_game = this;
		m_players[i]->Start();
	}

	//
	MiPoker_PlayGui* playGui = G_GuiMgr->GetGui<MiPoker_PlayGui>();
	if (playGui && playGui->IsAwake())
	{
		//自动出牌
		if(m_myPlayer)
			m_myPlayer->m_workingWithAI = playGui->m_textButtonOption[2]->GetState()==GCS_CLICK;
		//明牌
		m_openPoker = playGui->m_textButtonOption[3]->GetState()==GCS_CLICK;
	}

	//
	int myTurn = m_myRolePlayer?m_myRolePlayer->m_turn:0;
	m_players[myTurn]->m_screenPos = SP_Down;
	m_players[++myTurn%m_playerNum]->m_screenPos = SP_Right;
	m_players[++myTurn%m_playerNum]->m_screenPos = SP_Left;

	//进入miniplaygui,(选人、选关卡都已在房间里进行完毕)。
	//if(GetStyle()) G_GuiMgr->PushGui(GetStyle()->playGUI.c_str(),GL_DIALOG);

	return true;
}
bool PokerDouDiZhu::Stop()
{
	Free();
	return true;
}
bool PokerDouDiZhu::Update()
{
	PokerGame::Update();

	switch(m_gameStatus)
	{
	case Dealing:
		StateDealCard();
		break;
	case Preparing:
		{
			//call back
			if (G_Mouse->IsButtonDowning(MOUSE_LEFT))
			{
				if(Button_BeLord()) 
					return true;
				if(Button_NotBeLord()) 
					return true;
			}
		}
		break;
	case Playing:
		{
			CheckRoundEnd();
			
			if (G_Mouse->IsButtonDowning(MOUSE_LEFT))
			{
				//todo set ui visible  + call back
				if(Button_Pass()) 
					return true;
			}

			//call back
			if (G_Mouse->IsButtonDowning(MOUSE_RIGHT))
			{
				OnRButtonDown();
			}
		}
		break;
	case Resulting:
		{
			if (m_turnTime > 5)
			{
				if (m_bHost)
				{
					C2SPacketMiniGameCmd packet;
					packet.WriteHeader();
					packet.WriteValue(CMD_Restart);  
					G_MiniGame->SendPacketToOther(&packet);
				}

				Free();
				Start(); //send shuffle
			}
		}
		break;
	}


	return true;
}
bool PokerDouDiZhu::Render()
{
	PokerGame::Render();

	//if(m_gameStatus == Playing || m_gameStatus == Preparing)
	{
		//显示地主牌
		{
			int x, y;
			x =	Board2DCen.x - CardWidth * 5/2;
			y = G_PokerGame->BoardRect2D.y + RenderUpDownDistance;
			if(m_gameStatus == Playing)
			{
				for(int i = 0; i < 3; i++)
				{
					m_cardTexture[m_lordCard[i].cardID]->Bind();
					G_RendDriver->DrawTextureRect(RectF( x+i * 2 * CardWidth, y, CardWidth,CardHeight));
				}
			}
			else
			{
				//未叫显示背面
				for(int i = 0; i < 3; i++)
				{
					m_cardBackTexture->Bind();
					G_RendDriver->DrawTextureRect(RectF(x + i * 2 * CardWidth, y, CardWidth, CardHeight));
				}
			}
		}
	}

	if (m_gameStatus == Resulting)
	{
		if (m_myRolePlayer==NULL
			|| m_winnerTurn == m_myRolePlayer->m_turn
			|| (m_winnerTurn!=m_lordTurn && m_myRolePlayer->IsLord()==false) )
		{
			m_winTexture->Bind();
			G_RendDriver->DrawTextureRect(vec2(Board2DCen.x-m_winTexture->GetWidth()/2, Board2DCen.y-m_winTexture->GetHeight()/2));
		}
		else
		{
			m_loseTexture->Bind();
			G_RendDriver->DrawTextureRect(vec2(Board2DCen.x-m_loseTexture->GetWidth()/2, Board2DCen.y-m_loseTexture->GetHeight()/2));
		}

	}

	return true;
}




bool PokerDouDiZhu::CheckRoundEnd()
{
	//if(m_players[m_turn]->m_cardNum == 0)
	//{
	//	m_winnerTurn = m_turn;
	//	GameOver();
	//	return true;
	//}

	bool gameOver = false;
	for(int i = 0; i < m_playerNum; i++)
	{
		if(m_players[i]->m_cardNum == 0)
		{
			m_winnerTurn = i;
			gameOver = true;
		}
	}

	if(gameOver&&m_bHost)
	{
		int fen = 3;
		if(m_winnerTurn == m_lordTurn)
			fen = -3;
		//fen *= zhadan;
		for(int i = 0; i < m_playerNum; i++)
		{
			if(i!=m_lordTurn)
				m_players[i]->m_totalScore += fen ;
			else
				m_players[i]->m_totalScore -= fen*2;
		}


		char sound[256];
		if (m_winnerTurn == m_lordTurn)
		{
			sprintf(sound,"data/sound/poker/play_lord_win");
		}
		else
		{
			sprintf(sound,"data/sound/poker/play_farmer_win");
		}
		if (m_winnerTurn%2) //
			strcat(sound,"_femail.wav");
		else
			strcat(sound,".wav");
		m_players[m_winnerTurn]->m_sound->PlaySound__(sound);



		C2SPacketMiniGameCmd packet;
		packet.WriteHeader();
		packet.WriteValue(CMD_GameOver);  
		packet.WriteValue(m_winnerTurn); 
		G_MiniGame->SendPacketToOther(&packet);

		m_gameStatus = Resulting;
		m_turnTime = 0;
	}

	return gameOver;
}


//标记牌值
void PokerDouDiZhu::SignCard(Card *card)
{
	int id = card->cardID;
	if(id == JokerSmall)
	{
		card->cardValue = 16;
	}
	else if(id == JokerBig)
	{
		card->cardValue =  17;
	}
	else if(id >= 0 && id < JokerSmall)
	{
		card->cardValue = (id + 12) %13 + 3;
	}
}


void PokerDouDiZhu::StateDealCard()
{
	//另外三张决定地主后再发
	if (m_dealCardNum>=51)
	{
		for(int i = 0; i < m_playerNum; i++)
			m_players[i]->SortCard();
		m_gameStatus = Preparing;
		return;
	}

	m_dealAccumTime += G_Timer->GetStepTime();
	//0.1秒发一张
	if (m_dealAccumTime > m_dealCardNum*0.1f)
	{
		CardID cardID = (CardID)m_cardShuffle[m_dealCardNum];
		if (cardID>=0)
		{
			m_cardFlag[cardID] = InHand;
			int playerIndex = m_dealCardNum % m_playerNum;
			m_players[playerIndex]->RecvCard(cardID);
			m_dealCardNum++;
		}
		else
		{
			//host洗牌还没发下来
		}
	}
}


void PokerDouDiZhu::SendDecideLord(int turn)
{
	C2SPacketMiniGameCmd packet;
	packet.WriteHeader();
	packet.WriteValue(CMD_BeLord);  
	packet.WriteValue(m_turn); 
	//todo给lord发三张地主牌,目前是洗牌时已经发送
	G_MiniGame->SendPacketToOther(&packet);
}
void PokerDouDiZhu::DecideLord(int turn)
{
	m_lordTurn = turn;
	m_lastOutTurn = turn;
	m_turn = turn;
	m_turnTime = 0;
	m_gameStatus = Playing;

	for(int i = 0; i < 3; i++)
	{
		m_lordCard[i].cardID = (CardID)m_cardShuffle[i+CardNum-3];
	}
	//给地主发三张牌
	for(int i = 0; i < 3; i++)
		m_players[m_lordTurn]->RecvCard(m_lordCard[i].cardID);

	m_players[m_lordTurn]->SortCard();

	char sound[256];
	sprintf(sound,"data/sound/poker/call_jiaofeng_3");
	if (m_turn%2) //
		strcat(sound,"_femail.wav");
	else
		strcat(sound,".wav");
	if(m_myRolePlayer)
		m_myRolePlayer->m_sound->PlaySound__(sound);

}
//决定地主
void PokerDouDiZhu::StateDecideLord()
{
}

void PokerDouDiZhu::FirstOut()
{

}

//现存最大单牌
int  PokerDouDiZhu::MaxCard()
{
	if(m_cardFlag[JokerBig] != BeOut)
		return 17;
	if(m_cardFlag[JokerSmall] != BeOut)
		return 16;

	int max = 0;
	for(int i = 0; i < JokerSmall; i++)
	{
		if(m_cardFlag[i] != BeOut && max < (i +12) % 13)
			max = (i + 12) % 13 + 3;
	}
	return max;
}





void PokerDouDiZhu::OnRButtonDown()
{
	if(m_myRolePlayer==NULL
		||m_turn != m_myRolePlayer->m_turn)
		return;
	if(m_gameStatus != Playing)
		return;
	m_myRolePlayer->m_notOut = 0;//?
	if(m_gameStatus == Playing && m_myRolePlayer->TryOutCard())
	{
		OutCard(m_myRolePlayer);
		//if (CheckRoundEnd()==false)
		{
			C2SPacketMiniGameCmd packet;
			packet.WriteHeader();
			packet.WriteValue(CMD_OutCard);  
			packet.WriteValue(m_myRolePlayer->m_turn); 
			packet.WriteValue(m_curOutCards); 
			//
			packet.WriteValue(m_myRolePlayer->m_outNum); 
			for(int i = MaxPlayerCard - m_myRolePlayer->m_outNum; i < MaxPlayerCard; i++)
			{
				packet.WriteValue(m_myRolePlayer->m_cards[i].cardID);
			}
			G_MiniGame->SendPacketToOther(&packet);

			m_lastOutTurn = m_myRolePlayer->m_turn;
			NextTurn();
		}
	}
}



//人当地主
bool PokerDouDiZhu::Button_BeLord()
{
	if(m_myRolePlayer==NULL
		||m_turn != m_myRolePlayer->m_turn)
		return false;
	if(m_gameStatus != Preparing)
		return false;
	int ClickX = G_PokerGame->GetMousePos().x;
	int ClickY = G_PokerGame->GetMousePos().y;
	int buttonX = Board2DCen.x - 80;
	int buttonY = G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace-CardHeight-32;
	if(ClickX>buttonX  && ClickX<buttonX+m_sanfenButtonTexture->GetWidth() 
		&& ClickY>buttonY && ClickY < buttonY+m_sanfenButtonTexture->GetHeight())
	{
		G_PokerDouDiZhu->SendDecideLord(m_turn);
		DecideLord(m_myRolePlayer->m_turn);
		return true;
	}
	return false;
}

//人不当地主
bool PokerDouDiZhu::Button_NotBeLord()
{
	if(m_myRolePlayer==NULL
		||m_turn != m_myRolePlayer->m_turn)
		return false;
	if(m_gameStatus != Preparing)
		return false;
	int ClickX = G_PokerGame->GetMousePos().x;
	int ClickY = G_PokerGame->GetMousePos().y;
	int buttonX = G_Window->m_iWidth/2 + 20;
	int buttonY = G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace-CardHeight-32;
	if(ClickX>buttonX  && ClickX<buttonX+m_notbeLordButtonTexture->GetWidth() 
		&& ClickY>buttonY && ClickY < buttonY+m_notbeLordButtonTexture->GetHeight())
	{
		C2SPacketMiniGameCmd packet;
		packet.WriteHeader();
		packet.WriteValue(CMD_NotBeLord);  
		packet.WriteValue(m_myRolePlayer->m_turn); 
		G_MiniGame->SendPacketToOther(&packet);

		m_turn = (m_myRolePlayer->m_turn+1) % m_playerNum;
		m_turnTime = 0;
		//NextTurn()

		char sound[256];
		sprintf(sound,"data/sound/poker/call_bujiao");
		if (m_turn%2) //
			strcat(sound,"_femail.wav");
		else
			strcat(sound,".wav");
		m_myRolePlayer->m_sound->PlaySound__(sound);
		return true;
	}
	return false;
}
bool PokerDouDiZhu::Button_Pass()
{
	if(m_myRolePlayer==NULL
		||m_lastOutTurn == m_myRolePlayer->m_turn)
		return false;
	if(m_turn != m_myRolePlayer->m_turn)
		return false;
	if(m_gameStatus != Playing)
		return false;
	int ClickX = G_PokerGame->GetMousePos().x;
	int ClickY = G_PokerGame->GetMousePos().y;
	int buttonX = Board2DCen.x - 30;
	int buttonY = G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace-CardHeight-32;
	if(ClickX>buttonX  && ClickX<buttonX+m_passButtonTexture->GetWidth() 
		&& ClickY>buttonY && ClickY < buttonY+m_passButtonTexture->GetHeight())
	{
		C2SPacketMiniGameCmd packet;
		packet.WriteHeader();
		packet.WriteValue(CMD_Pass);  
		packet.WriteValue(m_myRolePlayer->m_turn); 
		G_MiniGame->SendPacketToOther(&packet);

		m_myRolePlayer->m_notOut = 1;
		NextTurn();

		char sound[256];
		sprintf(sound,"data/sound/poker/play_guo_%d",Rand()%2);
		if (m_turn%2) //
			strcat(sound,"_femail.wav");
		else
			strcat(sound,".wav");
		m_myRolePlayer->m_sound->PlaySound__(sound);
		return true;
	}
	return false;
}

int  PokerDouDiZhu::ProcessPacketCmd(PacketBase* packet)
{
	PokerGame::ProcessPacketCmd(packet);

	packet->SeekPos(PacketBase::HeadSize);
	int cmd;
	packet->ReadValue(cmd);
	switch(cmd)
	{
	case CMD_BeLord:
		{
			int turn = 0;
			packet->ReadValue(turn);
			DecideLord(turn);
		}
		break;
	case CMD_NotBeLord:
		{
			int turn = 0;
			packet->ReadValue(turn);
			m_turn = turn;
			NextTurn();

			char sound[256];
			sprintf(sound,"data/sound/poker/call_bujiao");
			if (m_turn%2) //
				strcat(sound,"_femail.wav");
			else
				strcat(sound,".wav");
			m_myRolePlayer->m_sound->PlaySound__(sound);
		}
		break;
	case CMD_Pass:
		{
			int turn = 0;
			packet->ReadValue(turn);
			m_turn = turn;
			m_players[m_turn]->m_notOut = true;
			NextTurn();

			char sound[256];
			sprintf(sound,"data/sound/poker/play_guo_%d",Rand()%2);
			if (m_turn%2) //
				strcat(sound,"_femail.wav");
			else
				strcat(sound,".wav");
			m_players[m_turn]->m_sound->PlaySound__(sound);
		}
		break;
	case CMD_OutCard:
		{
			int turn = 0;
			packet->ReadValue(turn);
			packet->ReadValue(m_curOutCards); 

			//
			int outNum;
			int cardID[MaxPlayerCard];
			packet->ReadValue(outNum); 
			for(int i = 0; i < outNum; i++)
			{
				packet->ReadValue(cardID[i]);
			}

			dynamic_cast<DouDizhuPlayer*>(m_players[turn])->ClickCardsID(cardID,outNum);

			m_turn = turn;
			m_lastOutTurn = turn;
			m_players[turn]->m_notOut = false;
			OutCard(m_players[turn]);

			NextTurn();
		}
		break;
	case CMD_GameOver:
		{
			int turn = 0;
			packet->ReadValue(turn);
			m_winnerTurn = turn;
			m_turnTime = 0;
			m_gameStatus = Resulting;

			char sound[256];
			if (m_winnerTurn == m_lordTurn)
			{
				sprintf(sound,"data/sound/poker/play_lord_win");
			}
			else
			{
				sprintf(sound,"data/sound/poker/play_farmer_win");
			}
			if (m_winnerTurn%2) //
				strcat(sound,"_femail.wav");
			else
				strcat(sound,".wav");
			m_players[m_winnerTurn]->m_sound->PlaySound__(sound);

		}
		break;
	case CMD_Restart:
		Free();
		Start();
		break;
	}
	return 0;
}



斗地主玩家派生类:

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerDouDiZhu.h
//  @Brief:     PokerDouDiZhu
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#if !defined(DouDizhuPlayer_h__)
#define DouDizhuPlayer_h__

#include "PokerGame.h"

class DouDizhuPlayer:public PokerPlayer
{
public:
	DouDizhuPlayer();
	virtual bool Start();
	//virtual void Update();
	virtual void Render();

	virtual void SortCard();		    //整牌
	virtual void OutCard();	

	bool IsLord();                      //是否地主
	bool IsMyTurn();                    //是否轮到

	CurOutCards* g_curOutCards;
};

class DouDizhuPlayerRobot:public DouDizhuPlayer
{
public:
	virtual bool Start();
	virtual void Update();
	virtual void Render();
	
	bool ThinkOutCard();				//出牌
	void OutFirst();					//先出
	bool OutFollow();					//跟牌
	
	void FirstLianZi();					//出串
	void FirstSanZhang();				//出三张,含三带一
	void FirstDuiZi();					//出对子
	void FirstDanZhang();				//出单牌
	void FirstZhaDan();					//出炸弹
	void FirstDanJoker();				//出单大王
	void FirstJoker();					//出双王
	bool searchDanJoker();				//查找是否有单王,且为大王
	bool searchJoker();					//查找是否有双王
	bool searchZhaDan();				//查找有无炸弹
	bool searchSanZhang();				//查找有无三张
	bool searchDuiZi();					//查找有无对子
	bool searchDanZhang();				//查找有无单张
	bool searchLianZi();				//查找有无连子

	bool FollowLianZi();				//跟连子
	bool FollowSanZhang();				//跟三张
	bool FollowSiDai2();				//出四带二
	bool FollowSanDaiYi();				//出三带一
	bool FollowDuiZi();					//跟对子
	bool FollowDanZhang();				//跟单牌
	bool FollowZhaDan();				//跟炸弹

	int m_position;					    //标记牌位置
	int m_lianziLen;					//顺子的长度
	int m_lianziLast;					//顺尾

};


class DouDizhuPlayerRole:public DouDizhuPlayerRobot
{
public:
	DouDizhuPlayerRole();
	virtual bool Start();
	virtual void Update();
	virtual void Render();
	virtual bool TryOutCard();						//出牌
	void SaveOutCard();					//保存待出的牌

	bool sd(int temp[]);				//是否三对,要求不同
	bool sfjdsd();						//三飞机带三对
	bool ld7();							//七连对
	bool ld6();							//六连对
	bool ld5();							//五连对
	bool fjd2d();						//飞机带2对
	bool sfjbd();						//三飞机不带
	bool sfjdsg();						//三飞机带三个
	bool ld(int temp[]);				//连对
	bool sd2d();						//四带二对
	bool ld4();							//四连对
	bool fjd2g();						//飞机带二个
	bool fjbd();						//飞机不带
	bool sd2g();						//三带二个
	bool ld3();							//三连对
	bool sz(int);						//顺子
	bool sd2();							//四带二
	bool zd();							//炸弹
	bool sd1();							//三带一
	bool sgbd();						//三个不带
	bool sw();							//双王
	bool dz();							//对子

	ToOutCardsDouDizhu*  m_toOutCard;	//准备要出的牌

	//int m_clickedNum;					//点击待出的牌数

};

#endif


//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerDouDiZhu.cpp
//  @Brief:     PokerDouDiZhu
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================

#include "General/Pch.h"
#include "General/Timer.h"
#include "General/Window.h"
#include "Input/InputMgr.h"
#include "Render/RendDriver.h"
#include "Poker/PokerDoudizhu.h"
#include "Poker/PokerGame.h"
#include "Poker/DouDiZhuPlayer.h"
#include "Poker/MiniGamePoker.h"
#include "Packet/PacketMiniGame.h"
#include "Sound/ChannelSound.h"
#include "Rpg/MiniGame.h"
#include "Gui/GuiMgr.h"
#include "Gui/GuiControlMisc.h"
#include "General/Pce.h"

//DouDizhuPlayer析构的时候报告过heap corruption detected:after normal block(#xxx) at 0x xxxxxxxx
//原因:DouDizhuPlayer* p = new DouDizhuPlayer;  ((DouDizhuPlayerRobot*)p)->m_toOutCard = ; 错误的静态强制转换会导致堆栈溢出。
DouDizhuPlayer::DouDizhuPlayer()
{
}

bool DouDizhuPlayer::Start()
{
	PokerPlayer::Start();
	m_notOut = 0;
	m_workingWithAI = false;
	return true;
}
void DouDizhuPlayer::Render()
{
	PokerPlayer::Render();

	int CardHeight=m_game->CardHeight;				
	int CardWidth=m_game->CardWidth;	

	Texture* texture;

	//switch()

	if(m_game->m_gameStatus == Playing
		&&IsLord())
	{
		//显示地主标志
		texture = G_PokerDouDiZhu->m_lordTexture;
		texture->Bind();

		if(m_screenPos == SP_Down)
		{
			G_RendDriver->DrawTextureRect(vec2(Board2DCen.x - texture->GetWidth()/2,  G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace));
		}
		else if(m_screenPos == SP_Right)
		{
			G_RendDriver->DrawTextureRect(vec2(G_PokerGame->BoardRect2D.GetRight()-RenderLeftRightSpace, Board2DCen.y - texture->GetHeight()));

		}
		else if(m_screenPos == SP_Left)
		{
			G_RendDriver->DrawTextureRect(vec2(G_PokerGame->BoardRect2D.x+RenderLeftRightSpace-texture->GetWidth(), Board2DCen.y - texture->GetHeight()));
		}
	}

	//显示不出状态
	if(m_notOut == 1)
	{
		int index = int(G_Timer->GetAccumTime()/10)%4;
		texture = m_game->m_passTexture[index];
		texture->Bind();
		if(m_screenPos == SP_Down)
		{
			int posY = G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace - CardHeight * 2;
			G_RendDriver->DrawTextureRect(vec2(Board2DCen.x ,  posY));
		}
		else if(m_screenPos == SP_Left)
		{
			G_RendDriver->DrawTextureRect(vec2(G_PokerGame->BoardRect2D.x+RenderLeftRightSpace+CardWidth*1.8f, Board2DCen.y - texture->GetHeight()));
		}
		else if(m_screenPos == SP_Right)
		{
			G_RendDriver->DrawTextureRect(vec2(G_PokerGame->BoardRect2D.GetRight()-RenderLeftRightSpace-CardWidth*2.8f, Board2DCen.y - texture->GetHeight()));
		}
	}

	//显示思考中
	if((m_game->m_gameStatus==Playing||m_game->m_gameStatus==Preparing)
		&&IsMyTurn())
	{
		//m_ctrlThink->SetVisible(true);
		int index = int(G_Timer->GetAccumTime()*10)%4;
		texture = m_game->m_thinkTexture[index];
		texture->Bind();

		if(m_screenPos == SP_Down)
		{
			G_RendDriver->DrawTextureRect(vec2(Board2DCen.x + 100 ,  G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace-CardHeight-texture->GetHeight()));
		}
		else if(m_screenPos == SP_Left)
		{
			G_RendDriver->DrawTextureRect(vec2(G_PokerGame->BoardRect2D.x+RenderLeftRightSpace+CardWidth, Board2DCen.y));
		}
		else if(m_screenPos == SP_Right)
		{
			G_RendDriver->DrawTextureRect(vec2(G_PokerGame->BoardRect2D.GetRight()-RenderLeftRightSpace-CardWidth-texture->GetWidth(), Board2DCen.y));
		}
	}



	//显示叫地主按钮
	if(G_PokerDouDiZhu->m_gameStatus == Preparing)
	{
		//显示叫地主按钮
		int posX;
		if(IsMyTurn())
		{
			if(m_screenPos == SP_Down)
			{
				G_PokerDouDiZhu->m_sanfenButtonTexture->Bind();
				G_RendDriver->DrawTextureRect(vec2(Board2DCen.x - 80, G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace-CardHeight-32));
				G_PokerDouDiZhu->m_notbeLordButtonTexture->Bind();
				G_RendDriver->DrawTextureRect(vec2(Board2DCen.x + 20, G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace-CardHeight-32));
			}
			else if(m_screenPos == SP_Left)
			{
				posX = G_PokerGame->BoardRect2D.x+RenderLeftRightSpace + CardWidth*1.8f; 
				G_PokerDouDiZhu->m_sanfenButtonTexture->Bind();
				G_RendDriver->DrawTextureRect(vec2(posX, Board2DCen.y - 80));
				G_PokerDouDiZhu->m_notbeLordButtonTexture->Bind();
				G_RendDriver->DrawTextureRect(vec2(posX, Board2DCen.y + 20));
			}
			else if(m_screenPos == SP_Right)
			{
				posX = G_PokerGame->BoardRect2D.GetRight() - RenderLeftRightSpace - CardWidth*2.8f; 
				G_PokerDouDiZhu->m_sanfenButtonTexture->Bind();
				G_RendDriver->DrawTextureRect(vec2(posX, Board2DCen.y - 80));
				G_PokerDouDiZhu->m_notbeLordButtonTexture->Bind();
				G_RendDriver->DrawTextureRect(vec2(posX, Board2DCen.y + 20));
			}
		}
		else
		{
			//显示叫地主状态
			if(m_screenPos == SP_Down)
			{
				G_PokerDouDiZhu->m_notbeLordTexture->Bind();
				int posY = G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace - CardHeight * 2;
				G_RendDriver->DrawTextureRect(vec2(Board2DCen.x, posY));
			}
			else if(m_screenPos == SP_Left)
			{
				posX = G_PokerGame->BoardRect2D.x+RenderLeftRightSpace + CardWidth*1.8f; 
				G_PokerDouDiZhu->m_notbeLordTexture->Bind();
				G_RendDriver->DrawTextureRect(vec2(posX, Board2DCen.y + 20));
			}
			else if(m_screenPos == SP_Right)
			{
				posX = G_PokerGame->BoardRect2D.GetRight() - RenderLeftRightSpace - CardWidth*2.8f; 
				G_PokerDouDiZhu->m_notbeLordTexture->Bind();
				G_RendDriver->DrawTextureRect(vec2(posX, Board2DCen.y + 20));
			}
		}
	}

}
void DouDizhuPlayer::SortCard()
{
	int i, j;
	int idi, idj;
	Card card;
	for(i = 0 ; i < m_cardNum ; i++)
	{
		for(j = i ; j < m_cardNum ; j++)
		{
			idi = m_cards[i].cardValue;
			idj = m_cards[j].cardValue;
			if(idj > idi
				||((idi == idj) && (m_cards[j].Color() > m_cards[i].Color()))
				)
			{
				card = m_cards[j];
				m_cards[j] = m_cards[i];
				m_cards[i] = card;
			}
		}
	}
}

bool DouDizhuPlayer::IsLord()
{
	return G_PokerDouDiZhu->m_lordTurn == m_turn;
}

bool DouDizhuPlayer::IsMyTurn()
{
	return G_PokerDouDiZhu->m_turn == m_turn;
}

void DouDizhuPlayer::OutCard()
{
	PokerPlayer::OutCard();

	if(m_bBaoPai==false
		&&m_cardNum <=2)
	{
		char sound[256];
		if(m_cardNum == 1)
		{
			sprintf(sound,"data/sound/poker/play_bao1");
		}
		if(m_cardNum == 2)
		{
			sprintf(sound,"data/sound/poker/play_bao2");
		}
		if (m_turn%2) //
			strcat(sound,"_femail.wav");
		else
			strcat(sound,".wav");
		m_sound->PlaySound__(sound);
		m_bBaoPai = true;
		return;
	}

	char sound[256];
	switch (g_curOutCards->type)
	{
	case GZ:
		sprintf(sound,"data/sound/poker/one_poker_%d",g_curOutCards->value-PokerDouDiZhu::Value3);
		break;
	case DZ:
		sprintf(sound,"data/sound/poker/two_poker_%d",g_curOutCards->value-PokerDouDiZhu::Value3);
		break;

	case SGBD:
		sprintf(sound,"data/sound/poker/play_3zhang");
		break;
	case SD1:
		sprintf(sound,"data/sound/poker/play_3dai1");
		break;
	case SD2:
		sprintf(sound,"data/sound/poker/play_3dai2");
		break;

	case SD2G:
	case SD2D:
		sprintf(sound,"data/sound/poker/play_4dai2");
		break;

	case SZ:
		sprintf(sound,"data/sound/poker/play_shun");
		break;

	case LD3:
		sprintf(sound,"data/sound/poker/play_sandui");
		break;
	case LD4:
	case LD5:
	case LD6:
	case LD7:
		sprintf(sound,"data/sound/poker/play_liandui");
		break;

	case FJBD:
	case FJD2G:
	case FJD2D:
	case SFJBD:
	case SFJDSG:
	case SFJDSD:
		sprintf(sound,"data/sound/poker/play_feiji");
		break;

	case ZD:
		sprintf(sound,"data/sound/poker/play_zhadan_%d",Rand()%3);
		break;
	case SW:
		sprintf(sound,"data/sound/poker/play_wangzha");
		break;
	default:
		sprintf(sound,"data/sound/poker/play_dani");
		break;
	}

	if (m_turn%2) //
	{
		strcat(sound,"_femail.wav");
	}
	else
	{
		strcat(sound,".wav");
	}
	m_sound->PlaySound__(sound);

	//播放出牌动作 todo 装备扑克道具
	if(m_movieCtrl)
	{
		String name = m_movieCtrl->GetRenderCharacterUI()->GetCurAnimName();
		if(name == "stand")
			 m_movieCtrl->GetRenderCharacterUI()->PlayAnim("attack");
		else
			 m_movieCtrl->GetRenderCharacterUI()->PlayAnim("stand");
	}
	//todo call back 播一次结束后恢复站位
}


bool DouDizhuPlayerRobot::Start()
{
	DouDizhuPlayer::Start();
	m_workingWithAI = true;
	return true;
}

void DouDizhuPlayerRobot::Update()
{
	PokerPlayer::Update();
	//if (m_bAI == true)


	if (m_game->m_turn == m_turn
		&& m_game->m_turnTime>1.0f //思考时间
		)
	{
		switch(m_game->m_gameStatus)
		{
		case Preparing:
			{
				int cardNum = 0;
				for(int i = 0; i < m_cardNum; i++)
				{
					if(m_cards[i].cardValue > PokerDouDiZhu::ValueA)
					{
						cardNum++;
					}
				}
				//有两张大牌,叫地主
				if(cardNum >= 2)
				{
					G_PokerDouDiZhu->SendDecideLord(m_turn);
					G_PokerDouDiZhu->DecideLord(m_turn);
					return;
				}
				else
				{
					//真实玩家都不叫
					if(Rand()%4==0)
					{
						G_PokerDouDiZhu->SendDecideLord(m_turn);
						G_PokerDouDiZhu->DecideLord(m_turn);
					}
					return;
				}
				m_game->NextTurn();

				C2SPacketMiniGameCmd packet;
				packet.WriteHeader();
				packet.WriteValue(CMD_NotBeLord);  
				packet.WriteValue(m_turn); 
				G_MiniGame->SendPacketToOther(&packet);


				char sound[256];
				sprintf(sound,"data/sound/poker/call_bujiao");
				if (m_turn%2) //
					strcat(sound,"_femail.wav");
				else
					strcat(sound,".wav");
				m_sound->PlaySound__(sound);
			}
			break;
		case Playing:
			{
				ThinkOutCard();
				if(m_notOut==false)
				{
					//out
					m_game->OutCard(this);
					//if (m_game->CheckRoundEnd()==false)
					{
						C2SPacketMiniGameCmd packet;
						packet.WriteHeader();
						packet.WriteValue(CMD_OutCard);  
						packet.WriteValue(m_turn); 
						packet.WriteValue(*g_curOutCards);  
						//
						packet.WriteValue(m_outNum); 
						for(int i = MaxPlayerCard - m_outNum; i < MaxPlayerCard; i++)
						{
							packet.WriteValue(m_cards[i].cardID);
						}
						G_MiniGame->SendPacketToOther(&packet);

						m_game->m_lastOutTurn = m_turn;
						m_game->NextTurn();
					}
				}
				else
				{
					//pass
					C2SPacketMiniGameCmd packet;
					packet.WriteHeader();
					packet.WriteValue(CMD_Pass);  
					packet.WriteValue(m_turn); 
					G_MiniGame->SendPacketToOther(&packet);

					m_game->NextTurn();

					char sound[256];
					sprintf(sound,"data/sound/poker/play_guo_%d",Rand()%2);
					if (m_turn%2) //
						strcat(sound,"_femail.wav");
					else
						strcat(sound,".wav");
					m_sound->PlaySound__(sound);

				}
			}
			break;
		}
	}
}

void DouDizhuPlayerRobot::Render()
{
	DouDizhuPlayer::Render();
}


bool DouDizhuPlayerRobot::ThinkOutCard()
{
	int LastOutTurn = G_PokerDouDiZhu->m_lastOutTurn;
	m_notOut = 1;
	AnalyseCard();
	if(LastOutTurn == m_turn)
	{
		OutFirst();
		m_notOut = 0;
	}
	else
	{
		int before = (m_turn + 2) % 3;
		int after  = (m_turn + 1) % 3;

		bool tryFollow = false;//要不要出牌
		if(IsLord())   
		{
			//自己是地主
			tryFollow = true;
		}
		else if(LastOutTurn == G_PokerDouDiZhu->m_lordTurn) 
		{
			//地主出的牌
			tryFollow = true;
		}
		else                                    
		{
			//非地主出的牌
			if(g_curOutCards->num==m_cardNum)//出牌可以赢 出完
			{
				tryFollow = true;
			}
			else if(m_cardNum <= 2)	//手里只有1、2张牌,快赢了
			{
				tryFollow = true;
			}
			else if(g_curOutCards->type == GZ && g_curOutCards->value <10) //出牌太小
			{
				tryFollow = true;
			}
			else if(g_curOutCards->type == DZ && g_curOutCards->value < 8) //出牌太小
			{
				tryFollow = true;
			}
		}

		if (tryFollow)
		{
			//是否划算:拆牌   王打三

			if(OutFollow())//能不能出牌
				m_notOut = 0;
		}
	}
	return true;
}


//先出算法
void DouDizhuPlayerRobot::OutFirst()
{
	//很少出4张,留着炸弹用

	//连子能找出飞机来?

	//先出得分最小的牌  可以被带的除外

	//出连子  连子太大也可以先不出  连到2 也可以只出一半
	if(searchLianZi())
	{
		FirstLianZi();
		return;
	}

	//出 单张 对子 三张中的较小者   单张数少的话考虑带
	OutType bestType = None;
	int     bestValue = 999;
	//单张
	if(searchDanZhang())
	{
		if (m_position<bestValue)
		{
			bestType = GZ;
			bestValue = m_position;
		}
	}
	//对子
	if(searchDuiZi())
	{
		if (m_position<bestValue)
		{
			bestType = DZ;
			bestValue = m_position;
		}
	}
	//三张
	if(searchSanZhang())
	{
		if (m_position<bestValue)
		{
			bestType = SGBD;
			bestValue = m_position;
		}
	}
	//恢复
	m_position = bestValue;
	//出单张
	if(bestType == GZ)
	{
		FirstDanZhang();
		return;
	}
	//出对子
	if(bestType == DZ)
	{
		FirstDuiZi();
		return;
	}
	//出三张
	if(bestType == SGBD)
	{
		FirstSanZhang(); //会带
		return;
	}


	//出炸弹
	if(searchZhaDan())
	{
		FirstZhaDan();
		return;
	}
	//出双王
	if(searchJoker())
	{
		FirstJoker();
		return;
	}
	//出单王
	if(searchDanJoker())
	{
		FirstDanJoker();
		return;
	}
	else
	{}
}


//跟牌算法
bool DouDizhuPlayerRobot::OutFollow()
{
	if(g_curOutCards->type == GZ)	//单张
	{
		if(FollowDanZhang()) 
			return true;	
		else
		{
			if(searchDanJoker())	//有王出之
			{
				FirstDanJoker();
				return true;
			}
			if(searchZhaDan())		//有炸弹出之
			{
				FirstZhaDan();
				return true;
			}			 
		}
	}
	else if(g_curOutCards->type == DZ)	//对子
	{
		if(FollowDuiZi()) 
			return true;
		else 
		{
			if(searchZhaDan())    //有炸弹出之
			{
				FirstZhaDan();
				return true;
			}
			else
			{
				if(searchJoker())//有双王出之
				{
					FirstJoker();
					return true;
				}
			}
		}
	}
	else if(g_curOutCards->type == SGBD)	//三张
	{
		if(FollowSanZhang())
			return true;
		else
		{
			if(searchZhaDan())	//有炸弹出之
			{
				FirstZhaDan();
				return true;
			}
			else if(searchJoker())	//有双王出之
			{
				FirstJoker();
				return true;
			}
		}
	}
	else if(g_curOutCards->type == SD1)	//三带一
	{
		if(FollowSanDaiYi())
			return true;
		else
		{
			if(searchZhaDan())    //有炸弹出之
			{
				FirstZhaDan();
				return true;
			}
			else if(searchJoker())	//有双王出之
			{
				FirstJoker();
				return true;
			}
		}
	}     
	else if(g_curOutCards->type == SZ)	//连子
	{
		if(FollowLianZi())
			return true;
		else
		{
			if(searchZhaDan())    //有炸弹出之
			{
				FirstZhaDan();
				return true;
			}
			else if(searchJoker())	//有双王出之
			{
				FirstJoker();
				return true;
			}; 
		}
	}
	else if(g_curOutCards->type == SD2G)	//四带二
	{
		if(FollowSiDai2())
			return true;
		else
		{
			if(searchZhaDan())	//有炸弹出之
			{
				FirstZhaDan();
				return true;
			}
			else if(searchJoker())	//有双王出之
			{
				FirstJoker();
				return true;
			}
		}
	}
	else if(g_curOutCards->type == ZD)	//炸弹
	{
		if(FollowZhaDan())
			return true;
		else
		{
			if(searchJoker())//有双王出之
			{
				FirstJoker();
				return true;
			}
		}
	}
	return false;
}

//出连子
void DouDizhuPlayerRobot::FirstLianZi()
{
	int start = m_lianziLast - m_lianziLen;	//连子开始组号
	int a1[12] = {0};
	int i = 0; 
	for( i = 0; start < m_lianziLast + 1; start++, i++)
	{
		a1[i] = start;
	}
	for(int j = 0; j < i + 1; j++)//改牌的状态为出了的
	{
		for(int k = 0;k < 20;k++)
		{
			if(m_cards[k].cardValue == a1[j])
			{
				m_cards[k].bClicked = true;
				break;
			}
		}
	}
	g_curOutCards->value = a1[i - 1];
	g_curOutCards->num = i;
	g_curOutCards->min = a1[0];
	g_curOutCards->type = SZ;
}

//出单张
void DouDizhuPlayerRobot::FirstDanZhang()
{
	for(int k = 0; k < 20; k++)//改牌的状态为出了的
	{
		if(m_cards[k].cardValue == m_position)
		{				
			m_cards[k].bClicked = 1;
			break;
		}
	}
	g_curOutCards->value = m_position;
	g_curOutCards->num = 1 ;
	g_curOutCards->type = GZ;
}

//出对子
void DouDizhuPlayerRobot::FirstDuiZi()
{
	int n = 0;
	for(int k = 0; k < 20; k++)//改牌的状态为出了的
	{
		if(m_cards[k].cardValue == m_position)
		{
			m_cards[k].bClicked = true;
			n++;
			if(n >= 2)
				break;
		}
	}
	g_curOutCards->value = m_position;
	g_curOutCards->num = 2;
	g_curOutCards->type = DZ;
}



//出三张
void DouDizhuPlayerRobot::FirstSanZhang()
{
	int i = m_position;
	assert(ValueCount[i] == 3);

	int j = 0;
	int bt = 0;
	while(!bt)
	{
		if(ValueCount[j] == 1 && j != i)
		{
			int a1[4] = {0};
			a1[0] = i;
			a1[1] = i;
			a1[2] = i;
			a1[3] = j;
			bt = 1;
			g_curOutCards->value = a1[0];
			g_curOutCards->num = 4;
			g_curOutCards->type = SD1;
			ClickCards(a1,g_curOutCards->num);
			return;
		}
		else 
		{
			j++;
			if(j>12)
			{
				int a1[3] = {0};
				a1[0] = i;
				a1[1] = i;
				a1[2] = i;
				g_curOutCards->value = a1[0];
				g_curOutCards->num = 3;
				g_curOutCards->type = SGBD;
				ClickCards(a1,g_curOutCards->num);
				return;
			}
		}       
	}    
}


//出炸弹
void DouDizhuPlayerRobot::FirstZhaDan()
{
	int n = 0;
	for(int k = 0; k < 20; k++)//改牌的状态为出了
	{
		if(m_cards[k].cardValue == m_position)
		{
			m_cards[k].bClicked = true;
			n++;
			if(n >= 4)
				break;
		}
	}
	g_curOutCards->value = m_position;
	g_curOutCards->num = 4;
	g_curOutCards->type = ZD;
}

//出双王
void DouDizhuPlayerRobot::FirstJoker()
{
	for(int k = 0; k < 20; k++)		//改牌的状态为出了的
	{
		if((m_cards[k].cardID == JokerSmall 
			|| m_cards[k].cardID == JokerBig) 
			&& m_cards[k].bClicked == false)
		{
			m_cards[k].bClicked = true;
		}
	}
	g_curOutCards->num = 2 ;
	g_curOutCards->value = 17;
	g_curOutCards->type = SW;
}

//出单大王
void DouDizhuPlayerRobot::FirstDanJoker()
{
	for(int k = 0; k < 20; k++)//改牌的状态为出了的
	{
		if(m_cards[k].cardValue == m_position)
		{
			m_cards[k].bClicked = true;
			break;
		}
	}
	g_curOutCards->value = m_position;
	g_curOutCards->num = 1;
	g_curOutCards->type = GZ;
}


//找单张,在顺子后找3---2
bool DouDizhuPlayerRobot::searchDanZhang()
{
	m_position = -1;	
	if(m_cardNum < 3 && !searchJoker())
	{
		//还剩两张
		int j = 0, a[2] = {0};
		for(int i = 0; i <= PokerDouDiZhu::ValueJokerBig; i++)
		{
			if(ValueCount[i] == 1)
				a[j++] = i;
		}

		//第二张最大
		if(a[1] == G_PokerDouDiZhu->MaxCard())
			m_position = a[1];
		else
			m_position = a[0];
	}
	else
	{
		//从小到大找
		for(int i = 0; i < PokerDouDiZhu::ValueJokerSmall; i++)
		{
			if(ValueCount[i] == 1)
			{
				m_position = i;
				break;    
			}
		}
	}
	if(m_position != -1) 
		return true;
	else 
		return false;
}

//找对子
bool DouDizhuPlayerRobot::searchDuiZi()
{
	m_position = -1;
	for(int i = 0; i < PokerDouDiZhu::ValueJokerSmall; i++)
	{
		if(ValueCount[i] == 2)
		{
			m_position = i;
			break;    
		}    
	}
	if(m_position != -1) 
		return true;
	else 
		return false;
}

//找三张
bool DouDizhuPlayerRobot::searchSanZhang()
{
	m_position = -1;

	for(int i = 0; i < PokerDouDiZhu::Value2; i++)
	{
		if(ValueCount[i] == 3)
		{
			m_position = i;
			break;    
		}    
	}
	if(m_position != -1) 
		return true;
	return false;   
}



//找炸弹
bool DouDizhuPlayerRobot::searchZhaDan()
{
	m_position = -1;
	for(int i = 0; i < PokerDouDiZhu::ValueJokerSmall; i++)
	{
		if(ValueCount[i] == 4)
		{
			m_position = i;
			break;    
		}    
	}

	if(m_position != -1) 
		return true; 
	return false;
}

//找双王
bool DouDizhuPlayerRobot::searchJoker()
{
	if(ValueCount[PokerDouDiZhu::ValueJokerBig] > 0 && ValueCount[PokerDouDiZhu::ValueJokerSmall] > 0)
	{
		return true;
	}
	return false;
}

//找连子
bool DouDizhuPlayerRobot::searchLianZi()
{
	int restValues[12] = {0};
	int maxLian = 0;
	m_lianziLast = -1;
	m_lianziLen = 1;
	for(int i = 0; i < PokerDouDiZhu::ValueQ; i++) //最大J可以连子
	{
		if(ValueCount[i] > 0) 
			restValues[maxLian++] = i;    //连续存放还有的牌value-3, value不再连续
	}

	//不会找出三连对,play时只会抽出一张
	for(int i = 0; i < maxLian - 1; i++)
	{
		if(restValues[i+1] == restValues[i]+1
			&& restValues[i]+1 < PokerDouDiZhu::Value2)
		{
			m_lianziLen++;
			if(m_lianziLen >= 5)
				m_lianziLast = restValues[i] + 1;
			//能连一直继续
			continue;
		}
		//不能继续连了
		if(m_lianziLen < 5) 
		{
			//打断连子,重新计数,继续
			m_lianziLen = 1;
			m_lianziLast = -1;
		}
		else
		{
			//已经找好
			return true;
		}
	}
	if(m_lianziLen < 5)
		return false;
	return true;
}

//找单大王
bool DouDizhuPlayerRobot::searchDanJoker()
{
	if(ValueCount[PokerDouDiZhu::ValueJokerBig] > 0 && ValueCount[PokerDouDiZhu::ValueJokerSmall] == 0)
	{
		m_position = PokerDouDiZhu::ValueJokerBig;
		return true;
	}
	return false;
}


//跟单张牌的情况
bool DouDizhuPlayerRobot::FollowDanZhang()
{
	//对手连出 或对手牌很少 拆牌必要性加大
	for(int i = g_curOutCards->value+1; i <= PokerDouDiZhu::ValueJokerBig ; i++)
	{
		if(ValueCount[i] == 1 
			|| (ValueCount[i] > 1 && i == PokerDouDiZhu::Value2)	//多个2可拆
			//|| //地主牌仅剩1张
			//|| 上家是地主 或自己是地主 上家一直破单张作弊
			)
		{
			int a1[1] = {0};
			a1[0] = i;
			ClickCards(a1,g_curOutCards->num);	//出牌后对玩家手中的牌进行相应清理
			g_curOutCards->value = a1[0];
			g_curOutCards->num = 1 ;
			g_curOutCards->type = GZ;
			return true;
		}
	}
	return false;
}

//跟对子
bool DouDizhuPlayerRobot::FollowDuiZi()
{
	//不同时期 剩余牌数不同 评分标准也不同

	//对手连出 或对手牌很少 拆牌必要性加大
	for(int i = g_curOutCards->value+1; i <= PokerDouDiZhu::Value2; i++)
	{
		if(ValueCount[i]==2 
			|| (ValueCount[i] > 2 && i == PokerDouDiZhu::Value2)   //多个2可拆
			//|| (ValueCount[i] > 2 && i>= PokerDouDiZhu::ValueA)  //多个>A可拆   对2没有时再拆A
			//|| //地主牌仅剩2张
			)
		{
			int a1[2] = {0};
			a1[0] = i;
			a1[1] = i;
			ClickCards(a1,g_curOutCards->num);		//出牌后对玩家手中的牌进行相应清理
			g_curOutCards->value = a1[0] ;
			g_curOutCards->num = 2;
			g_curOutCards->type = DZ;
			return 1;
		}
	}
	return 0;
}


//跟三张
bool DouDizhuPlayerRobot::FollowSanZhang()
{
	for(int i = g_curOutCards->value+1; i <= PokerDouDiZhu::Value2; i++)
	{
		if(ValueCount[i] == 3)
		{
			int a1[3] = {0};
			a1[0] = i;
			a1[1] = i;
			a1[2] = i;
			ClickCards(a1,g_curOutCards->num);
			g_curOutCards->value = a1[0];
			g_curOutCards->num = 3;
			g_curOutCards->type = SGBD;
			return true;
		}
	}
	return false;
}

//跟连子
bool DouDizhuPlayerRobot::FollowLianZi()
{
	int lens = 1;
	int end = 0;
	for(int i = g_curOutCards->value+1; i < PokerDouDiZhu::ValueQ && lens < g_curOutCards->num; i++)
	{
		for(int j = 0; j < g_curOutCards->num; j++, i++)
			if(ValueCount[i] > 0)
			{
				lens++;
				if(j == g_curOutCards->num - 1)
					end = i;
			}
			else
			{
				lens = 1;
				break;
			}
	}
	//找到匹配的连子
	if(lens == g_curOutCards->num)
	{
		int start = -1;
		start = end - g_curOutCards->num + 1;	//连子开始组号
		int a1[12] = {0};
		int i = 0; 
		for( i = 0; i < g_curOutCards->num; i++)
			a1[i] = start++;
		ClickCards(a1,g_curOutCards->num);
		g_curOutCards->value = a1[i];
		g_curOutCards->min = a1[0];
		g_curOutCards->num = i - 1;
		g_curOutCards->type = SZ;
		return true;
	}
	//未找到匹配的连子
	else   
		return false;
}

//四带二只能带对子
bool DouDizhuPlayerRobot::FollowSiDai2()
{
	//4个2 不用作带牌?todo更智能的判断
	for(int i = g_curOutCards->value+1; i < PokerDouDiZhu::Value2; i++)
	{
		if(ValueCount[i] == 4)
		{
			int j = 0;
			int bt = 0;
			while(!bt)
			{
				if(ValueCount[j] == 2)
				{
					int a1[8] = {0};
					int ans = i;    
					for(int k = 0; k < 4; k++)
						a1[k] = ans++;    
					a1[4] = j;
					a1[5] = j + 1;
					ClickCards(a1,g_curOutCards->num); 
					bt = 1;
					g_curOutCards->value = a1[0];
					g_curOutCards->num = 8;
					g_curOutCards->type = SD2G;
					return true;
				}
				else 
				{
					j++;
					if(j > 12)
					{
						bt = 1;
						return false;
					} 
				}       
			} 
		}
	}    
	return false;
}

//用炸弹炸掉
bool DouDizhuPlayerRobot::FollowZhaDan()
{
	//4个2 用作炸弹?
	for(int i = g_curOutCards->value+1; i <= PokerDouDiZhu::Value2; i++)
	{
		if(ValueCount[i] == 4)
		{
			int a1[4] = {0};
			int ans = i;   
			for(int k = 0; k < 4; k++)
				a1[k] = ans++;
			ClickCards(a1,g_curOutCards->num); 
			g_curOutCards->value = a1[0];
			g_curOutCards->num = 4;
			g_curOutCards->type = ZD;
			return true;
		}
	}
	return false;
}
//出三带一
bool DouDizhuPlayerRobot::FollowSanDaiYi()
{
	for(int i = g_curOutCards->value+1; i < PokerDouDiZhu::Value2; i++)
	{
		if(ValueCount[i] == 3)
		{
			int j = 0;
			int bt = 0;
			while(!bt)
			{
				if(ValueCount[j] == 1 && j != i)
				{
					int a1[4] = {0};
					a1[0] = i;
					a1[1] = i;
					a1[2] = i;
					a1[3] = j;
					bt = 1;
					g_curOutCards->value = a1[0];
					g_curOutCards->num = 4;
					g_curOutCards->type = SD1;
					ClickCards(a1,g_curOutCards->num); 
					return true;
				}
				else 
				{
					j++;
					if(j > 12) 
						return false;
				}       
			}    
		}
	}
	return false;
}




DouDizhuPlayerRole::DouDizhuPlayerRole()
//:m_clickedNum(0)
{

}

bool DouDizhuPlayerRole::Start()
{
	DouDizhuPlayerRobot::Start();
	m_workingWithAI = false;
	return true;
}


void DouDizhuPlayerRole::Update()
{
	if (m_workingWithAI == true)
	{
		DouDizhuPlayerRobot::Update();
	}
	else
	{

		if (m_game->m_turn == m_turn)
		{
			switch(m_game->m_gameStatus)
			{
			case Preparing:
				{
					//if (G_Mouse->IsButtonDowning(MOUSE_LEFT))
					//{
					//	if(Button_BeLord()) return;
					//	if(Button_NotBeLord()) return;
					//}
				}
				break;
			case Playing:
				{
					//if (G_Mouse->IsButtonDowning(MOUSE_LEFT))
					//{
					//	//todo set ui visible  + call back
					//	if(Button_Pass()) 
					//		return true;
					//	m_myRolePlayer->ClickCard(this->GetMousePos());
					//}

					//if (G_Mouse->IsButtonDowning(MOUSE_RIGHT))
					//{
					//	OnRButtonDown();
					//}

					if (G_PokerGame->IsButtonDowning(MOUSE_LEFT))
					{
						ClickCard(G_PokerGame->GetMousePos());
					}
				}
				break;
			}
		}
	}
}


void DouDizhuPlayerRole::Render()
{
	//PokerPlayer::Render();
	DouDizhuPlayerRobot::Render();


	int CardHeight=m_game->CardHeight;				
	int CardWidth=m_game->CardWidth;	

	//显示不出按钮
	{
		if(m_game->m_turn == m_turn 
			&& m_game->m_lastOutTurn != m_turn
			&& m_game->m_gameStatus == Playing)
		{
			m_game->m_passButtonTexture->Bind();	
			G_RendDriver->DrawTextureRect(vec2(Board2DCen.x - 30, G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace-CardHeight-32));
		}

	}

	//if(m_game->m_gameStatus == Playing
	//	&&IsLord())
	//{
	//	//显示地主
	//	G_PokerDouDiZhu->m_isLordTexture->Bind();
	//	if(m_screenPos == SP_Down)
	//	{
	//		G_RendDriver->DrawTextureRect(vec2(Board2DCen.x - 33,  G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace));
	//	}
	//}

	显示叫地主按钮
	//{
	//	if(IsMyTurn()
	//		&& G_PokerDouDiZhu->m_gameStatus == Preparing)
	//	{
	//		G_PokerDouDiZhu->m_sanfenButtonTexture->Bind();
	//		G_RendDriver->DrawTextureRect(vec2(Board2DCen.x - 80, G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace));
	//		G_PokerDouDiZhu->m_buJiaoButtonTexture->Bind();
	//		G_RendDriver->DrawTextureRect(vec2(Board2DCen.x + 20, G_PokerGame->BoardRect2D.GetBottom()-RenderUpDownSpace));
	//	}
	//}
}


//保存待出的牌
void DouDizhuPlayerRole::SaveOutCard()
{
	for(int i = 0; i < MaxPlayerCard; i++)
		m_toOutCard->m_cards[i].cardID = (CardID)-1;

	int num = 0;
	for(int i = 0; i < m_cardNum; i++)
	{
		if(m_cards[i].bClicked == true)
		{
			m_toOutCard->m_cards[num++] = m_cards[i];	
		}
	}
	m_toOutCard->m_cardNum = num;
}

bool DouDizhuPlayerRole::TryOutCard()
{
	if(m_clickedNum <= 0)
		return false;

	SaveOutCard();
	int tmp = g_curOutCards->value;
	if(G_PokerDouDiZhu->m_lastOutTurn != m_turn)
	{
		switch(m_clickedNum)
		{
		case 0:	
			return false;
		case 1:
			{
				if(g_curOutCards->type == GZ && m_toOutCard->m_cards[0].cardValue > g_curOutCards->value)
				{
					g_curOutCards->value = m_toOutCard->m_cards[0].cardValue;
					g_curOutCards->num = 1;
					g_curOutCards->type = GZ;
					return true;
				}
			} 
		case 2:	
			{
				if(g_curOutCards->type == DZ && dz())	//是不是对子
				{
					if(tmp < m_toOutCard->m_cards[0].cardValue)
						return true; 
				}
				if(sw())
					return true;
			}
		case 3:
			{
				if(g_curOutCards->type == SGBD && sgbd())
					if(tmp < m_toOutCard->m_cards[0].cardValue)
						return 1; 
			}
		case 4:	
			{
				if(g_curOutCards->type == SD1 && sd1())
				{
					if(tmp < m_toOutCard->m_cards[1].cardValue)
						return true;  
				}
				if(g_curOutCards->type != ZD && zd())
					return true;  
				if(g_curOutCards->type == ZD && zd())
				{
					if(tmp < m_toOutCard->m_cards[1].cardValue)
						return true;
				}
			}
		case 5:	
			{
				if(g_curOutCards->type == SZ && sz(5))
					if(tmp < m_toOutCard->m_cards[0].cardValue)
						return true;
				if(g_curOutCards->type == SD2 && sd2())
					if(tmp < m_toOutCard->m_cards[2].cardValue)
						return true;
			} 
		case 6: 
			{
				if(g_curOutCards->type == SZ && sz(6))
					if(tmp < m_toOutCard->m_cards[0].cardValue)
						return true;
				if(g_curOutCards->type == LD3 && ld3())
					if(tmp < m_toOutCard->m_cards[5].cardValue)
						return true;
				if(g_curOutCards->type == SD2G && sd2g())
					if(tmp < m_toOutCard->m_cards[3].cardValue)
						return true;
				if(g_curOutCards->type == FJBD && fjbd())
					if(tmp < m_toOutCard->m_cards[4].cardValue)
						return true;
			} 
		case 7:	
			{
				if(g_curOutCards->type == SZ && sz(7))
					if(tmp < m_toOutCard->m_cards[0].cardValue)
						return true;
			} 
		case 8:	
			{
				if(g_curOutCards->type == SZ && sz(8))
					if(tmp < m_toOutCard->m_cards[0].cardValue)
						return true;
				if(g_curOutCards->type == FJD2G && fjd2g())
					if(tmp < m_toOutCard->m_cards[2].cardValue)
						return true;
				if(g_curOutCards->type == LD4 && ld4())
					if(tmp < m_toOutCard->m_cards[7].cardValue)
						return true;
				if(g_curOutCards->type == SD2G && sd2d())
					return true;

			}
		case 9:	
			{
				if(g_curOutCards->type == SZ && sz(9))
					if(tmp < m_toOutCard->m_cards[0].cardValue)
						return true;
				if(g_curOutCards->type == SFJBD && sfjbd())
					if(tmp < m_toOutCard->m_cards[8].cardValue)
						return true;
			} 
		case 10:return sz(10) || fjd2d() || ld5(); 
		case 11:return sz(11); 
		case 12:return sz(12) || ld6() || sfjdsg();
		case 13:return sz(13);
		case 14:return ld7();
		case 15:return sfjdsd();
		default: return false; 
		}
	}
	else
	{
		switch(m_clickedNum)
		{
		case 0:	return false ; 
		case 1:
			{
				g_curOutCards->value = m_toOutCard->m_cards[0].cardValue;
				g_curOutCards->num = 1;
				g_curOutCards->type = GZ;
			}
			return true; 
		case 2:	return dz() || sw(); 
		case 3:	return sgbd(); 
		case 4:	return sd1() || zd(); 
		case 5:	return sz(5) || sd2(); 
		case 6: return sz(6) || ld3() || sd2g() || fjbd();
		case 7:	return sz(7);
		case 8:	return sz(8) || fjd2g() || ld4() || sd2d();
		case 9:	return sz(9) || sfjbd(); 
		case 10: return sz(10) || fjd2d() || ld5(); 
		case 11: return sz(11); 
		case 12: return sz(12) || ld6() || sfjdsg();
		case 13: return sz(13);
		case 14: return ld7();
		case 15: return sfjdsd();
		default: return false;
		}
	}
	return false;
}


//对子
bool DouDizhuPlayerRole::dz()
{
	if(m_toOutCard->m_cards[0].cardValue == m_toOutCard->m_cards[1].cardValue)
	{
		g_curOutCards->value = m_toOutCard->m_cards[0].cardValue;
		g_curOutCards->num = 2;
		g_curOutCards->type = DZ;
		return true; 
	}
	return false ; 
}

//双王
bool DouDizhuPlayerRole::sw()
{
	if(m_toOutCard->m_cards[0].cardValue + m_toOutCard->m_cards[1].cardValue == 33)			//记得改成和这个一样的
	{
		g_curOutCards->num =2;
		g_curOutCards->type = SW;
		return true; 
	}
	return false ; 
}

//三个不带
bool DouDizhuPlayerRole::sgbd()
{
	if(m_toOutCard->m_cards[0].cardValue == m_toOutCard->m_cards[1].cardValue && m_toOutCard->m_cards[1].cardValue == m_toOutCard->m_cards[2].cardValue)
	{
		g_curOutCards->value = m_toOutCard->m_cards[0].cardValue;
		g_curOutCards->num =3;
		g_curOutCards->type = SGBD;
		return true; 
	}	
	return false; 
}

//三带一
bool DouDizhuPlayerRole::sd1()
{
	int analyse[2] , m = 0 , n = 0 , i , j , k , num = 5 ; 
	for(i = 0 ; i < num ; i++)
		for(j = i+1 ; j < num ; j++)
			for(k = j+1 ; k < num ; k++)
			{
				if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue && m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue)
				{
					for(m = 0 ; m < num ; m++)
					{
						if(m !=  i  &&  m !=  j  &&  m !=  k)
							analyse[n++] = m_toOutCard->m_cards[m].cardValue; 
					}
					if(analyse[0] != m_toOutCard->m_cards[i].cardValue)
					{
						g_curOutCards->value = m_toOutCard->m_cards[i].cardValue;
						g_curOutCards->num = 3;
						g_curOutCards->type = SD1;
						return true; 
					}
					else 
						return false ; 
				}
			}
			return false; 
}

//炸弹
bool DouDizhuPlayerRole::zd()
{
	if(m_toOutCard->m_cards[0].cardValue == m_toOutCard->m_cards[1].cardValue 
		&& m_toOutCard->m_cards[1].cardValue == m_toOutCard->m_cards[2].cardValue 
		&& m_toOutCard->m_cards[2].cardValue == m_toOutCard->m_cards[3].cardValue)
	{
		g_curOutCards->value = m_toOutCard->m_cards[0].cardValue;
		g_curOutCards->num = 4;
		g_curOutCards->type = ZD;
		return true; 
	}
	else
		return false; 
}

//三带二
bool DouDizhuPlayerRole::sd2()
{
	int analyse[2] , m = 0 , n = 0 , i , j , k , num = 5 ; 
	for(i = 0 ; i < num ; i++)
		for(j = i+1 ; j < num ; j++)
			for(k = j+1 ; k < num ; k++)
			{
				if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue && m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue)
				{
					for(m = 0 ; m < num ; m++)
					{
						if(m !=  i  &&  m !=  j  &&  m !=  k)
							analyse[n++] = m_toOutCard->m_cards[m].cardValue; 
					}
					if(analyse[0] == analyse[1])
					{
						g_curOutCards->value = m_toOutCard->m_cards[i].cardValue;
						g_curOutCards->num =4;
						g_curOutCards->type = SD2;
						return true; 
					}
					else 
						return false; 
				}
			}
			return false; 
}

//顺子  n 代表牌数
bool DouDizhuPlayerRole::sz(int n)
{
	int i ; 
	for(i = 0 ; i < n-1 ; i++)
	{
		if(m_toOutCard->m_cards[i].cardValue == PokerDouDiZhu::Value2
			|| m_toOutCard->m_cards[i + 1].cardValue == PokerDouDiZhu::Value2)
			return false; 不能有2
		if(m_toOutCard->m_cards[i].cardValue != m_toOutCard->m_cards[i + 1].cardValue + 1)
			return false; 
	}
	g_curOutCards->value = m_toOutCard->m_cards[0].cardValue;
	g_curOutCards->min = m_toOutCard->m_cards[n -1].cardValue;
	g_curOutCards->num = n;
	g_curOutCards->type = SZ;
	return true;
}

//连对3  (三连对)
bool DouDizhuPlayerRole::ld3()
{
	int min = m_toOutCard->MinCard(); //不能为KA2 (13 14 15)
	if(min == 13)
		return false; 
	if(m_toOutCard->CountCard(min) == 2 && m_toOutCard->CountCard(min + 1) == 2 && m_toOutCard->CountCard(min + 2) == 2)
	{
		g_curOutCards->value = min;
		g_curOutCards->num = 6;
		g_curOutCards->type = LD3;
		return true; 
	}
	return false; 
}

//四带二个
bool DouDizhuPlayerRole::sd2g()
{
	int analyse[2], m = 0, n = 0, i, j, k, p; 
	for(i = 0; i < 6; i++)
		for(j = i+1; j < 6; j++)
			for(k = j+1; k < 6; k++)
				for(p = k+1; p < 6; p++)
				{
					if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue 
						&& m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue 
						&& m_toOutCard->m_cards[k].cardValue == m_toOutCard->m_cards[p].cardValue)
					{
						for(n = 0, m = 0; m < 6; m++)
						{
							if(m !=  i && m != j && m != k && m != p)
								analyse[n++] = m_toOutCard->m_cards[m].cardValue;
						}
						if(analyse[0] != analyse[1])
						{
							g_curOutCards->value = m_toOutCard->m_cards[i].cardValue;
							g_curOutCards->num =6;
							g_curOutCards->type = SD2G;
							return true; 
						}
						return false; 
					}
				}
				return false;
}

//飞机不带
bool DouDizhuPlayerRole::fjbd()
{
	int analyse[3], m = 0, n = 0, i, j, k, num = 6;
	for(i = 0; i < num ; i++)
		for(j = i + 1; j < num; j++)
			for(k = j + 1; k < num; k++)
			{
				if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue && m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue)
				{
					for(n = 0, m = 0; m < num; m++)
					{
						if(m != i && m != j && m != k)
							analyse[n++] = m_toOutCard->m_cards[m].cardValue;
					}
					if(analyse[0] == analyse[1] && analyse[1] == analyse[2])//判断另外三个是否相等
					{
						if(abs(m_toOutCard->m_cards[i].cardValue - analyse[0]) !=  1)
							return false;	//当两个三个不是连着的时
						if(((m_toOutCard->m_cards[i].cardValue > analyse[0]) ? m_toOutCard->m_cards[i].cardValue : analyse[0]) == PokerDouDiZhu::Value2)
							return false;	//最大不能为2
						g_curOutCards->value = m_toOutCard->m_cards[i].cardValue < analyse[0] ? m_toOutCard->m_cards[i].cardValue : analyse[0];
						g_curOutCards->num =6;
						g_curOutCards->type = FJBD;
						return true; 
					}
					return false; 
				}
			}
			return false;
}
//飞机带二个
bool DouDizhuPlayerRole::fjd2g()
{
	int analyse[2], m = 0, n = 0, i, j, k, t[2][3] = {0}, num = 8; 
	for(i = 0; i < num; i++)
	{
		for(j = i+1; j < num; j++)
		{
			for(k = j+1; k < num; k++)
			{
				if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue && m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue)
				{
					t[n][0] = i; 
					t[n][1] = j; 
					t[n++][2] = k; 
				}
				if(n == 2)
				{
					if(abs(m_toOutCard->m_cards[t[0][0]].cardValue - m_toOutCard->m_cards[t[1][0]].cardValue) != 1)
						return false;		//当两个三个不是连着的时
					for(n = 0, m = 0; m < num; m++)
					{
						if(m != t[0][0] && m != t[0][1] && m != t[0][2] 
						&& m != t[1][0] && m != t[1][1] && m != t[1][2])
							analyse[n++] = m_toOutCard->m_cards[m].cardValue;
					}
					if(analyse[0] != analyse[1])
					{
						if((m_toOutCard->m_cards[t[0][0]].cardValue < m_toOutCard->m_cards[t[1][0]].cardValue ? m_toOutCard->m_cards[t[0][0]].cardValue : m_toOutCard->m_cards[t[1][0]].cardValue) == 14)
							return false;		//最大不能为2
						g_curOutCards->value = m_toOutCard->m_cards[t[0][0]].cardValue < m_toOutCard->m_cards[t[1][0]].cardValue ? m_toOutCard->m_cards[t[0][0]].cardValue : m_toOutCard->m_cards[t[1][0]].cardValue;
						g_curOutCards->num = 8;
						g_curOutCards->type = FJD2G;
						return true; 
					}
					return false; 
				}
			}
		}
	}
	return false;
}

//4连对
bool DouDizhuPlayerRole::ld4()
{
	int min = m_toOutCard->MinCard();
	if(min == 12)
		return false;	//最大不能为2
	if(m_toOutCard->CountCard(min) == 2 && m_toOutCard->CountCard(min+1) == 2 
		&& m_toOutCard->CountCard(min + 2) == 2  &&  m_toOutCard->CountCard(min + 3) == 2)
	{
		g_curOutCards->value = min;
		g_curOutCards->num = 8;
		g_curOutCards->type = LD4;
		return true;
	}
	return false;
}

//四带两对
bool DouDizhuPlayerRole::sd2d()
{
	int analyse[4], m = 0, n = 0, i, j, k, p; 
	for(i = 0; i < 8; i++)
		for(j = i+1; j < 8; j++)
			for(k = j+1; k < 8; k++)
				for(p = k+1; p < 8; p++)
				{
					if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue 
						&& m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue 
						&& m_toOutCard->m_cards[k].cardValue == m_toOutCard->m_cards[p].cardValue)
					{
						for(n = 0, m = 0; m < 8; m++)
						{
							if(m != i && m != j && m != k && m != p)
								analyse[n++] = m_toOutCard->m_cards[m].cardValue;
						}
						if(ld(analyse))	
						{
							g_curOutCards->value = m_toOutCard->m_cards[i].cardValue;
							g_curOutCards->num = 8;
							g_curOutCards->type = SD2D;
							return true;
						}
						return false;
					}
				}
				return false;
}


//是不是二对 , 要求不一样
bool DouDizhuPlayerRole::ld(int temp[])
{
	int i, j, m, n = 0, analyse[2], num = 4;
	for (i = 0; i < num; i++)
		for (j = i+1 ; j < num ; j++)
		{
			if(temp[i] == temp[j])
				for(m = 0 ; m < num ; m++)
				{
					if(m != i && m != j)
						analyse[n++] = temp[m];
				}
				if(analyse[0] == analyse[1] && analyse[0] != temp[i])
				{
					return true;
				}
		}
		return false;
}





//三飞机带三个
bool DouDizhuPlayerRole::sfjdsg()
{
	int analyse[3], m = 0, n = 0, i, j, k, t[3][3] = {0}, num = 12; 
	for(i = 0; i < num ; i++)
		for(j = i+1; j < num; j++)
			for(k = j+1; k < num; k++)
			{
				if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue 
					&& m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue)
				{
					t[n][0]  =  i; 
					t[n][1]  =  j; 
					t[n++][2] = k; 
				}
				if(n == 3)
				{
					for(n = 0, m = 0; m < num; m++)
					{
						if(m != t[0][0] && m != t[0][1] && m != t[0][2] 
						&& m != t[1][0] && m != t[1][1] && m != t[1][2]
						&& m != t[2][0] && m != t[2][1] && m != t[2][2])
							analyse[n++] = m_toOutCard->m_cards[m].cardValue ; 
					}
					if(analyse[0] != analyse[1] && analyse[0] != analyse[2] && analyse[2] != analyse[1])
					{
						analyse[0] = m_toOutCard->m_cards[t[0][0]].cardValue; 
						analyse[1] = m_toOutCard->m_cards[t[1][0]].cardValue; 
						analyse[2] = m_toOutCard->m_cards[t[2][0]].cardValue; 
						if((analyse[0] + analyse[1] + analyse[2]) != (MinCard(analyse, 3) + 1) * 3) 
							return false; //三个是不是连着的
						if(MinCard(analyse, 3) == 13) 
							return false; //最大不能为2
						g_curOutCards->value = MinCard(analyse, 3);
						g_curOutCards->num =12;
						g_curOutCards->type = SFJDSG;
						return  true; 
					}
					return false ; 
				}
			}
			return false;
}

//三飞机不带
bool DouDizhuPlayerRole::sfjbd()
{
	int min = m_toOutCard->MinCard(); 
	if(min == 13) 
		return false; //最大不能为2
	if(    m_toOutCard->CountCard(min) == 3 
		&& m_toOutCard->CountCard(min + 1) == 3 
		&& m_toOutCard->CountCard(min + 2) == 3)
	{
		g_curOutCards->value = min;
		g_curOutCards->num = 9;
		g_curOutCards->type = SFJBD;
		return true; 
	}
	return false; 
}

//飞机带两对
bool DouDizhuPlayerRole::fjd2d()
{
	int analyse[4], m = 0, n = 0, i, j, k, t[3][3] = {0}, num = 10; 
	for(i = 0; i < num; i++)
		for(j = i+1; j < num; j++)
			for(k = j+1; k < num; k++)
			{
				if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue 
					&& m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue)
				{
					t[n][0] = i; 
					t[n][1] = j; 
					t[n++][2] = k; 
				}
				if(n == 2)
				{
					if(abs(m_toOutCard->m_cards[t[0][0]].cardValue - m_toOutCard->m_cards[t[1][0]].cardValue) != 1) 
						return false; //当两个三个不是连着的时
					for(n = 0, m = 0; m < num; m++)
					{
						if(m != t[0][0] && m != t[0][1] && m != t[0][2] && m != t[1][0] && m != t[1][1] && m != t[1][2])
							analyse[n++] = m_toOutCard->m_cards[m].cardValue; 
					}
					if(ld(analyse))
					{
						if(((m_toOutCard->m_cards[t[0][0]].cardValue < m_toOutCard->m_cards[t[1][0]].cardValue) 
							? m_toOutCard->m_cards[t[0][0]].cardValue : m_toOutCard->m_cards[t[1][0]].cardValue) == 14) 
							return false; //最大不能为2
						g_curOutCards->value = m_toOutCard->m_cards[t[0][0]].cardValue < m_toOutCard->m_cards[t[1][0]].cardValue 
							? m_toOutCard->m_cards[t[0][0]].cardValue : m_toOutCard->m_cards[t[1][0]].cardValue;
						g_curOutCards->num =10;
						g_curOutCards->type = FJD2D;
						return true; 
					}
					return false; 
				}
			}
			return false;
}

//五连对
bool DouDizhuPlayerRole::ld5()
{
	int min = m_toOutCard->MinCard(); 
	if(min == 11) 
		return false; //最大不能为2
	if(    m_toOutCard->CountCard(min) == 2      && m_toOutCard->CountCard(min + 1) == 2 
		&& m_toOutCard->CountCard(min + 2) == 2  && m_toOutCard->CountCard(min + 3) == 2 
		&& m_toOutCard->CountCard(min + 4) == 2)
	{
		g_curOutCards->value = min;
		g_curOutCards->num =10;
		g_curOutCards->type = LD5;
		return true; 
	}
	return false; 
}
//六连对
bool DouDizhuPlayerRole::ld6()
{
	int min = m_toOutCard->MinCard(); 
	if(min == 10)
		return false;	//最大不能为2
	if(    m_toOutCard->CountCard(min) == 2     && m_toOutCard->CountCard(min + 1) == 2
		&& m_toOutCard->CountCard(min + 2) == 2 && m_toOutCard->CountCard(min + 3) == 2
		&& m_toOutCard->CountCard(min + 4) == 2 && m_toOutCard->CountCard(min + 5) == 2)
	{
		g_curOutCards->value = min;
		g_curOutCards->num =12;
		g_curOutCards->type = LD6;
		return true;
	}
	return false;
}

//七连对
bool DouDizhuPlayerRole::ld7()
{
	int min = m_toOutCard->MinCard();
	if(min == 9)
		return false;	//最大不能为2
	if(    m_toOutCard->CountCard(min) == 2     && m_toOutCard->CountCard(min + 1) == 2
		&& m_toOutCard->CountCard(min + 2) == 2 && m_toOutCard->CountCard(min + 3) == 2
		&& m_toOutCard->CountCard(min + 4) == 2 && m_toOutCard->CountCard(min + 5) == 2
		&& m_toOutCard->CountCard(min + 6) == 2)
	{
		g_curOutCards->value = min;
		g_curOutCards->num =14;
		g_curOutCards->type = LD7;
		return true;
	}
	return false;
}

//三飞机带三对
bool DouDizhuPlayerRole::sfjdsd()
{
	int analyse[6], m = 0, n = 0, i, j, k, t[3][3] = {0}, num = 15;
	for(i = 0; i < num; i++)
		for(j = i+1; j < num; j++)
			for(k = j+1; k < num; k++)
			{
				if(m_toOutCard->m_cards[i].cardValue == m_toOutCard->m_cards[j].cardValue 
					&& m_toOutCard->m_cards[j].cardValue == m_toOutCard->m_cards[k].cardValue)
				{
					t[n][0] = i;
					t[n][1] = j;
					t[n++][2] = k;
				}
				if(n == 3)
				{
					for(n = 0, m = 0; m < num; m++)
					{
						if(m != t[0][0] && m != t[0][1] && m != t[0][2]
						&& m != t[1][0] && m != t[1][1] && m != t[1][2]
						&& m != t[2][0] && m != t[2][1] && m != t[2][2])
							analyse[n++] = m_toOutCard->m_cards[m].cardValue;
					}
					if(sd(analyse))
					{
						analyse[0] = m_toOutCard->m_cards[t[0][0]].cardValue;
						analyse[1] = m_toOutCard->m_cards[t[1][0]].cardValue;
						analyse[2] = m_toOutCard->m_cards[t[2][0]].cardValue;
						if((analyse[0] + analyse[1] + analyse[2]) != (MinCard(analyse, 3) + 1) * 3)
							return false;	//三个是不是连着的
						if(MinCard(analyse, 3) == 13)
							return false;	//最大不能为2
						g_curOutCards->value = MinCard(analyse, 3);
						g_curOutCards->num =15;
						g_curOutCards->type = SFJDSD;
						return true; 
					}
					return false;
				}
			}
			return false;
}

//是不是三对, 要求不一样
bool DouDizhuPlayerRole::sd(int temp[])
{
	int i, j, m = 0, n = 0, num = 6, t[3];
	for (i = 0; i < num; i++)
		for (j = i+1 ; j < num ; j++)
		{
			if(temp[i] == temp[j])
				t[m++] = j;
			if((m > 1) && (temp[t[m - 2]] == temp[t[m - 1]]))	//除出三个一样的
				return false;
		}
		if(m == 3)
			return true;
		return false;
}

蜘蛛纸牌代码:

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerHongXin.cpp
//  @Brief:     SpiderGame
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================

#ifndef _SpideGame_
#define _SpideGame_

#include "Math/MathLib.h"
#include "General/Vector.h"
#include "Render/Texture.h"
#include "PokerCard.h"
#include "Rpg/MiniGame.h"

typedef Vector<int> IntVector;

struct	ScreenStruct			
{
	char LbFrom;	   //牌从该列移出
	char LbTo;		   //移出的牌移到该列
	char MoveCardNum;  //拖动牌数
	int  nBackNum;     //主列牌的覆盖牌数
};

enum SpiderGameStatus
{
	Waiting,
	Dealing,   //发牌
	Completing,//收牌
	Tiping,
	Playing,
	Resulting,
};

#define DOWNPOS (BoardRect2D.y + BoardRect2D.height - 30)		//分数区域底部位置
#define CARDDIS_BACK  17 //8	//未翻牌重叠间距高度
#define CARDDIS_FRONT 20		//翻开牌重叠间距高度
#define CardWidth  71
#define CardHeight 96

class SoundChannel;

//顶部的一列牌
class Every
{
public:
	int  CardAt(int index);
	void PushCard(int card);
	void DeleteCard(int index);
	//某一个牌是否上一张牌小
	bool IsLessThenTop(int index);

	//计算最大可拖动牌数
	int  CalMaxMoveNum();

	RectF CardRect(int index);

	int  m_index;
	IntVector m_cards;          //所有牌
	int  m_backNum;				//未翻牌数
	int  m_maxMoveNum;          //最大可拖动牌数
};

class MiniGameSpiderPoker:public MiniGame
{
public:
	MiniGameSpiderPoker();
	virtual~MiniGameSpiderPoker();

	virtual bool Start();
	virtual bool Stop();
	virtual bool Render();
	virtual bool Update();
	virtual bool Free();

	//三种类型结构
	virtual MiniPlayer*  CreatePlayer();
	virtual MiniPlayer*  CreateRobot ();
	virtual MiniPlayer*  CreateRole  ();

	//发牌过程函数
	bool OnDeal();

	//根据给定牌的列和链表,计算出可以拖动的矩形大小
	void GetRecvRect(Every*every,RectF &rect);

	//判断拖动牌的个数
	int GetMoveCardNum(Every*every,const vec2& point);

	//计算拖动牌左上角坐标和鼠标按下点坐标的横纵距离
	void GetTwoPointJL(Every*every,const vec2& point);

	//判断一列牌中是否可以收牌
	void IsCardAccess(Every*ever);

	//提示功能
	bool OnTip();

	void OnUndo();
	void OnGameRead();
	void OnGameSave();

	//判断是否胜利
	bool IsGameEnd();


	//增加一个撤消状态
	void AddScreen(char CardList,char CardListOther,char MoveCardNum,int BackNum);

	void DebugCheck();


public:
	SpiderGameStatus   m_gameStatus;
	float   m_stateAccumeTime;

	
#define MaxEveryNum 10
	int EveryNum;
	//十列牌
	Every m_cardEverys[MaxEveryNum];

	IntVector  m_cardsDealLeft;			//剩余牌链表
	IntVector  m_cardsComplete;			//已经完成的牌

	int m_dealLeft;						//剩余发牌轮数

	Every*  m_curDealEvery;
	vec2 m_curDealPoint; 	    //发牌或收牌的起点和终点
	vec2 m_curDealPointEnd;
	int  m_curDealCardVal;

	Every*  m_curCompleteEvery;
	vec2 m_curCompletePoint; 	//发牌或收牌的起点和终点
	vec2 m_curCompletePointEnd;
	int  m_curCompleteCardNum;
	int  m_curCompleteCardVal;

	int m_moveComplete;			//已完成的列数

	int m_Score;				//总分数
	int m_moveNum;				//拖动次数


	bool m_tipButton;
	bool m_dealButton;

	//撤消功能
	ScreenStruct * m_undos;				
	int m_curUndo;				//当前屏幕号
	int m_MaxScreen;			//记录的最大屏幕数

	float EveryDis;				//列间距
	bool m_openPoker;

private:

	vec2I m_moveOffset;			//鼠标点和拖动牌左上角的偏移
	int   m_curMoveNum;			//跟随鼠标拖动牌个数

	Every*   m_curMoveEvery;	//拖动的列

	IntVector  m_movingCards;	//拖动的牌

	//存储牌拖动信息
	IntVector  m_tipMoves;		//依次存储当前列、对比列、当前列与对比列可以拖动牌的个数
	int m_curTip;				//当前可拖动牌信息个数,值为1到一拖动牌信息个数最大值

	TexturePtr m_texCards[CardNum];
	TexturePtr m_texCardBack;
	TexturePtr m_texCardSlot;
	TexturePtr m_texBack;
	SoundChannel*  m_sound;
};

extern MiniGameSpiderPoker* G_SpiderGame;

#endif 

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Poker/PokerHongXin.cpp
//  @Brief:     SpiderGame
//  @Author:     LouLei
//  @Email:  [email protected]
//  @Copyright (Crapell) - All Rights Reserved
//========================================================

#include "General/Pch.h"
#include "General/Timer.h"
#include "General/Window.h"
#include "MiniGameSpiderPoker.h"
#include "Input/InputMgr.h"
#include "Render/RendDriver.h"
#include "Render/Font.h"
#include "Sound/ChannelSound.h"
#include "General/Vector.cpp"
#include "General/Pce.h"
#include "Render/MC_MovieClip.h"
#include "Render/Camera.h"
#include "Gui/GuiMgr.h"
#include "Gui/RpgGuis.h"
#include "Render/Shader.h"

template class Vector<int>;
MiniGameSpiderPoker* G_SpiderGame = NULL;
MiniGameSpiderPoker::MiniGameSpiderPoker()
{
    G_SpiderGame = this;
    m_MaxScreen	=	50;
    m_undos	=	new ScreenStruct[m_MaxScreen];
    m_sound = new SoundChannel;
}
MiniGameSpiderPoker::~MiniGameSpiderPoker()
{
    SafeDeleteArray(m_undos);
    SafeDelete(m_sound);
    G_SpiderGame = NULL;
}

bool MiniGameSpiderPoker::Start()
{
    if(!MiniGame::Start())
        return false;

	m_openPoker = false;

    const char* cardTexName[] =
    {
        "data/minigame/poker/mei2.png",
        "data/minigame/poker/mei3.png",
        ...
    };
    for(int i = 0; i < CardNum; i++)
    {
        G_TextureMgr->AddTexture(m_texCards[i], cardTexName[i]);
    }
    G_TextureMgr->AddTexture(m_texCardBack, "data/minigame/poker/cardback01.png");
    G_TextureMgr->AddTexture(m_texCardSlot, "data/minigame/poker/cardslot.png");
    G_TextureMgr->AddTexture(m_texBack, "data/minigame/poker/back.png");
    //
    if(m_movieScene == NULL)
    {
        LoadConfig loader(LoadConfig::GenDonotReShrinkBound, true, true);
        m_movieScene = new RendSys::MovieClip;
        m_movieScene->LoadFromFile("data/minigame/poker/board.movie", &loader);
		Frame frame;
		frame.SetPos(m_startPos);
		m_movieScene->SetProgramFrame(&frame);
		m_movieScene->Advance();
    }
    if(m_movieScene->IsLoadComplete() == false)
    {
        m_gameState = MS_End;
        return false;
    }
    SetBoardRect(RectF(100, 100, G_Window->m_iWidth-200, G_Window->m_iHeight-200),
                 RectF(m_startPos.x - 50, m_startPos.z - 33, 100, 66),
                 m_startPos.y + 10.1f);

	EveryNum        =  10;
    m_moveNum		=	0;
    m_Score			=	0;
    m_moveComplete	=	0;
    m_curUndo	    =	0;
    m_undos[0].LbFrom	=	0;
    m_undos[0].LbTo	=	0;
    m_undos[0].MoveCardNum	=	0;
    m_curMoveEvery		=	0;
    m_curTip =	0;
    EveryDis = (BoardRect2D.width - CardWidth * EveryNum) / 11;		//利用总距离减去牌的总宽度
    //先清除所有链表中数据
    for(int i = 0; i < EveryNum; i++)
    {
        m_cardEverys[i].m_cards.clear();
		m_cardEverys[i].m_maxMoveNum	=	0;
		m_cardEverys[i].m_index	=	i;
    }
    m_cardsDealLeft.clear();
    m_movingCards.clear();
    104张牌数组
    int level = Rand()%2+1;
	//int level = 1;
    if(level == 1)
    {
        //单色
        for(int i = 0; i < 8; i++)
        {
            for(int j = 1; j <= 13; j++)
            {
                m_cardsDealLeft.push_back(j);
            }
        }
    }
    else if(level == 2)
    {
        //双色
        for(int i = 0; i < 4; i++)
        {
            for(int j = 1; j <= 26; j++)
            {
                m_cardsDealLeft.push_back(j);
            }
        }
    }
    //else if (level ==3)
    //{
    //	//4色
    //	for(int i=0;i<2;i++)
    //	{
    //		for(int j=1;j<=52;j++)
    //		{
    //			m_cardsDealLeft.push_back(j);
    //		}
    //	}
    //}
    刷牌: 随机i-1中的任意一个数与i交换
    //for (int i = 2; i < 104; i++)
    //{
    //	int ran = Rand()%i;
    //	char temp = m_cardsDealLeft[ran];
    //	m_cardsDealLeft[ran] = m_cardsDealLeft[i];
    //	m_cardsDealLeft[i] = temp;
    //}

    //设置10个列的牌
    while(true)
    {
        if(m_cardsDealLeft.size() == 60)
            break;
        for(int i = 0; i < EveryNum; i++)
        {
            if(m_cardsDealLeft.size() == 60)
                break;
            m_cardEverys[i].m_cards.push_back(m_cardsDealLeft.back());
            m_cardsDealLeft.pop_back();
        }
    }
    DebugCheck();
    //给每列未翻的牌个数赋值
    for(int i = 0; i < EveryNum; i++)
    {
		if (m_cardEverys[i].m_cards.size()>0)
		{
			m_cardEverys[i].m_backNum = m_cardEverys[i].m_cards.size()-1;
		}
		else
		{
			m_cardEverys[i].m_backNum = 0;
		}
    }
    //给剩余发牌次数和已完成列牌次数赋值
    m_dealLeft		=	6;
    m_moveComplete	=	0;
    //分数和拖动数重新计算
    m_Score	=	500;
    m_moveNum =	0;
    OnDeal();

	//进入miniplaygui,(选人、选关卡都已在房间里进行完毕)。
	if(GetStyle()) G_GuiMgr->PushGui(GetStyle()->playGUI.c_str(),GL_DIALOG);

	//
	for(int i = 0; i < m_allPlayerNum; i++)
	{
		if(m_miniPlayer[i])
			m_miniPlayer[i]->Start();
	}

	//设置摄像机
	CameraCtrlerTarget* ctrler = new CameraCtrlerTarget;
	ctrler->SetDistToTar(60);
	ctrler->SetTarPos(m_startPos);
	G_Camera->PushCtrler(ctrler);
	G_Camera->SetEuler(0, -60, 0);
	//片头摄像机
	PushIntroCamera();

    return true;
}

MiniPlayer* MiniGameSpiderPoker::CreatePlayer()
{
	return NULL;//new ChessPlayer;
}

MiniPlayer* MiniGameSpiderPoker::CreateRobot()
{
	return NULL;// new ChessPlayerRobot;
}

MiniPlayer* MiniGameSpiderPoker::CreateRole()
{
	//m_myRolePlayer = NULL;//new ChessPlayerRole;
	//return m_myRolePlayer;
	return NULL;
}

bool MiniGameSpiderPoker::Stop()
{
    {
        if(m_myPlayer && m_myPlayer->m_liveNum > 0)
        {
            G_GuiMgr->GetGui<Rpg_ResultDialog>()->ShowResult(true);
        }
        else
        {
            G_GuiMgr->GetGui<Rpg_ResultDialog>()->ShowResult(false);
        }
        G_GuiMgr->PushGui("Rpg_ResultDialog", GL_DIALOGBOTTOM);
    }
    return MiniGame::Stop();
}
bool MiniGameSpiderPoker::Update()
{
    SetBoardRect(RectF(100, 100, G_Window->m_iWidth-200, G_Window->m_iHeight-200),
                 RectF(m_startPos.x - 50, m_startPos.z - 33, 100, 66),
                 m_startPos.y + 10.1f);
	EveryDis = (BoardRect2D.width - CardWidth * 10) / 11;		//利用总距离减去牌的总宽度

    if(m_3dMode)
    {
        m_movieScene->Advance();
    }
    if(G_Keyboard->IsKeyUping(DIK_Z) && G_Keyboard->IsKeyPressed(DIK_LCONTROL))
    {
        OnUndo();
    }
    if(m_gameStatus == Playing)
    {
        vec2 pos = this->GetMousePos();
        //if (G_Mouse->IsButtonPressed(MOUSE_LEFT))
        {
            RectF rect;
            //提示
            rect.x   = BoardRect2D.x + BoardRect2D.width / 2 - 100;
            rect.y    = DOWNPOS - 100;
            rect.width  = 200;
            rect.height = 100;
            if(rect.IsPointIn(pos))
            {
                m_tipButton = true;
            }
            else
            {
                m_tipButton = false;
            }
            //发牌
            rect.x   = BoardRect2D.x + BoardRect2D.width - EveryDis - (m_dealLeft - 1) * CARDDIS_BACK - CardWidth;
            rect.y    = DOWNPOS - CardHeight;
            rect.width  = CardWidth;
            rect.height = CardHeight;
            if(rect.IsPointIn(pos))
            {
                m_dealButton = true;
            }
            else
            {
                m_dealButton = false;
            }
        }
        if(G_Mouse->IsButtonDowning(MOUSE_LEFT))
        {
            //拖动牌
            RectF rect;
            for(int m = 0; m < EveryNum; m++)
            {
                //得到需要跟随牌的个数
                m_curMoveNum	=	GetMoveCardNum(&m_cardEverys[m], pos);
                //按下点在矩形区域内,并且当前列有元素
                if(m_curMoveNum > 0)
                {
                    m_curMoveEvery = &m_cardEverys[m];
                    //计算鼠标点和拖动牌左上角坐标的距离
                    GetTwoPointJL(m_curMoveEvery, pos);
                    int nCount	= m_curMoveEvery->m_cards.size();
                    //删除指定列中被拖动的牌
                    for(int i = 1; i <= m_curMoveNum; i++)
                    {
                        m_movingCards.push_back(m_curMoveEvery->m_cards.at(nCount - i));
                        m_curMoveEvery->DeleteCard(nCount - i);
                    }
                    break;
                }
            }
            //提示
            if(m_tipButton)
            {
                OnTip();
                m_gameStatus = Tiping;
                m_stateAccumeTime = 0;
            }

            //发牌
            if(m_dealButton)
            {
                OnDeal();
            }
        }
        if(G_Mouse->IsButtonUping(MOUSE_LEFT))
        {
            if(m_movingCards.size() > 0)
            {
                RectF rectSave;					//可以接收列的范围
                RectF rectCard;					//列牌可拖动的矩形区域
                bool bMoveSuccess =	false;		//是否在当前列中加了临时数组的牌
                for(int i = 0; i < EveryNum; i++)
                {
					Every* it = &m_cardEverys[i];
                    //计算可接收拖动牌的范围
                    GetRecvRect(it, rectCard);
                    rectSave.x	=	rectCard.x - EveryDis / 2;
                    rectSave.width	=	rectCard.width	+ EveryDis;
                    rectSave.y	=	rectCard.y;
                    rectSave.height	=	rectCard.height + CardHeight;
                    int nCount		=	it->m_cards.size();
                    int nCount1		=	m_movingCards.size();
					if (rectSave.IsPointIn(pos))
					{
						if((nCount	==	0 || m_curMoveEvery == it))
						{
							bMoveSuccess	=	true;
						}
						else
						{
							int toCard = -1;
							if(nCount > 0)
								toCard = it->m_cards.at(nCount - 1);
							int moveCard = m_movingCards.at(nCount1 - 1);
							if(    toCard == (moveCard + 1) 
								|| toCard == (moveCard + 1 + 13) 
								|| toCard == (moveCard + 1 - 13)
								)
							{
								bMoveSuccess	=	true;
							}
						}
					}
                  
                    if(bMoveSuccess)
                    {
                        //在新列牌中加入拖动过来的牌
                        for(int j = m_movingCards.size(); j > 0; j--)
						{
                            it->PushCard(m_movingCards.at(j - 1));
						}
                        AddScreen(m_curMoveEvery->m_index, i, m_movingCards.size(), m_curMoveEvery->m_backNum);
   
                        //移完翻牌
                        if(m_curMoveEvery->m_cards.size() == m_curMoveEvery->m_backNum
                                && m_curMoveEvery->m_backNum > 0)
                        {
                            m_curMoveEvery->m_backNum	-=	1;
                        }
                        m_curMoveEvery->CalMaxMoveNum();

                        //分数和拖动牌次数更新
                        if(it != m_curMoveEvery)
                        {
                            m_moveNum++;
                            m_Score	--;
                        }
                        //收牌
                        IsCardAccess(it);
                        break;
                    }
                }
                //拖动失败
                if(bMoveSuccess == false)
                {
                    for(int j = m_movingCards.size(); j > 0; j--)
                        m_curMoveEvery->PushCard(m_movingCards.at(j - 1));
                }
                //清空拖动牌
                m_movingCards.clear();
            }
        }
    }
    return true;
}

bool MiniGameSpiderPoker::Free()
{
    MiniGame::Free();
    return true;
}
void MiniGameSpiderPoker::DebugCheck()
{
    return;
    for(int c = 1; c <= 26; c++)
    {
        int num = 0;
        for(int i = 0; i < 10; i++)
        {
            for(int j = 0; j < m_cardEverys[i].m_cards.size(); j++)
            {
                if(m_cardEverys[i].m_cards[j] == c)
                {
                    num++;
                }
            }
        }
        for(int j = 0; j < m_cardsDealLeft.size(); j++)
        {
            if(m_cardsDealLeft[j] == c)
            {
                num++;
            }
        }
        if(num != (8 - m_moveComplete) && num != 0)
        {
            int a = 0;
        }
    }
}

int  Value2CardID(int value)
{
    if(value == 1)
    {
        return HONGTA;
    }
    else if(2 <= value && value <= 13)
    {
        return HONGT2 + value - 2;
    }
    else if(value == 14)
    {
        return HEITA;
    }
    else if(15 <= value && value <= 26)
    {
        return HEIT2 + value - 15;
    }
    return JokerBig;
};

bool MiniGameSpiderPoker::Render()
{
    if(m_3dMode)
    {
        G_RendDriver->EndUI();
        if(m_movieScene == NULL
                || m_movieScene->IsLoadComplete() == false)
            return false;
        m_movieScene->RendClip();
        G_RendDriver->PushMatrix();
        G_RendDriver->MultMatrix(mat2Dto3D);
        if(G_ShaderMgr && G_ShaderMgr->m_curEffect)
        {
            G_ShaderMgr->m_picked = false;
            //todo  每个物体单独设置 没必要
            //G_ShaderMgr->m_doReceiveShadow = m_doReceiveShadow;
            G_ShaderMgr->MapChangeParm();
        }
    }
    else
    {
        G_RendDriver->BeginUI();
        if(G_ShaderMgr && G_ShaderMgr->m_curEffect)
        {
            G_ShaderMgr->m_picked = false;
            //todo  每个物体单独设置 没必要
            //G_ShaderMgr->m_doReceiveShadow = m_doReceiveShadow;
            G_ShaderMgr->MapChangeParm();
        }
        //背景 
        G_RendDriver->ShaderColor4f(1, 1, 1, 1);
        G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST, false);
        m_texBack->Bind();
        G_RendDriver->DrawTextureRect(BoardRect2D);
    }

    //10列牌的槽位
    G_RendDriver->ShaderColor4f(1, 1, 1, 1);
    m_texCardSlot->Bind(); 
    for(int i = 0; i < EveryNum; i++)
    {
		if(m_cardEverys[i].m_cards.size()==0)
		{
			G_RendDriver->DrawTextureRect(m_cardEverys[i].CardRect(0));
		}
    }
    //显示分数和点击数
    //brush.CreateSolidBrush(RGB(0,255,150));
    //画矩形
    if(m_gameStatus == Playing && m_tipButton)
    {
        G_RendDriver->ShaderColor4f(0, 1, 0, 1);
    }
    else
    {
        G_RendDriver->ShaderColor4f(1, 1, 1, 1);
    }
    G_RendDriver->DrawTextureRect(RectF(BoardRect2D.x+BoardRect2D.width / 2 - 100,
                                        DOWNPOS - 100,
                                        200, 100));
    G_RendDriver->ShaderColor4f(1, 1, 1, 1);
    String str;
    str.format("score: %d", m_Score);
    G_FontMgr->TextAtPos(vec2(BoardRect2D.x+BoardRect2D.width / 2 - 30, DOWNPOS - 80), str.c_str());	//显示分数
    str.format("move: %d", m_moveNum);
    G_FontMgr->TextAtPos(vec2(BoardRect2D.x+BoardRect2D.width / 2 - 30, DOWNPOS - 60), str.c_str());	//显示操作数

    //显示所有牌
    {
        //绘制10列牌
        for(int m = 0; m < EveryNum; m++)
        {
			//未翻的牌
			if (m_openPoker)//作弊显示翻开
			{
				G_RendDriver->ShaderColor4f(0.3f, 1, 0.5f, 1); 
			} 
			else
			{
				G_RendDriver->ShaderColor4f(1, 1, 1, 1);
			}
            int backNum = m_cardEverys[m].m_backNum;
            m_texCardBack->Bind();
            for(int i = 0; i < backNum; i++)
            {
				if (m_openPoker)//作弊显示翻开
				{
					m_texCards[Value2CardID(m_cardEverys[m].m_cards[i])]->Bind();
				}
                G_RendDriver->DrawTextureRect(m_cardEverys[m].CardRect(i));
            }

			//翻开的牌
            G_RendDriver->ShaderColor4f(1, 1, 1, 1);
            int frontNum = m_cardEverys[m].m_cards.size() - backNum;
            for(int i = 0; i < frontNum; i++)
            {
                m_texCards[Value2CardID(m_cardEverys[m].m_cards[backNum + i])]->Bind();
                G_RendDriver->DrawTextureRect(m_cardEverys[m].CardRect(i+backNum));
            }
        }
        //下面可发牌
        m_texCardBack->Bind();
        for(int i = 0; i < m_dealLeft; i++)
        {
            if(i == m_dealLeft - 1 && m_gameStatus == Playing && m_dealButton)
            {
                G_RendDriver->ShaderColor4f(0, 1, 0, 1);
            }
            else
            {
                G_RendDriver->ShaderColor4f(1, 1, 1, 1);
            }
            int x = BoardRect2D.x + BoardRect2D.width - EveryDis - i * CARDDIS_BACK - CardWidth;
            int y = DOWNPOS - CardHeight;
            G_RendDriver->DrawTextureRect(RectF(x, y, CardWidth, CardHeight));
        }
        G_RendDriver->ShaderColor4f(1, 1, 1, 1);
        //左下已完成列
        for(int i = 0; i < m_moveComplete; i++)
        {
            if(m_cardsComplete.at(i) == 1)
                m_texCards[HONGTK]->Bind();
            else
                m_texCards[HEITK]->Bind();
            int x	=	BoardRect2D.x + EveryDis + i * CARDDIS_BACK;
            int y	=	DOWNPOS - CardHeight;
            G_RendDriver->DrawTextureRect(RectF(x, y, CardWidth, CardHeight));
        }
        int moveNum	=	m_movingCards.size();
        vec2 point = this->GetMousePos();
        //拖动的牌
        for(int i = 0; i < moveNum; i++)
        {
            m_texCards[Value2CardID(m_movingCards[moveNum - i - 1])]->Bind();
            G_RendDriver->DrawTextureRect(RectF(point.x - m_moveOffset.x, point.y + i * CARDDIS_FRONT - m_moveOffset.y, CardWidth, CardHeight));
        }
    }
    m_stateAccumeTime += G_Timer->GetStepTimeLimited();
    if(m_gameStatus == Tiping)
    {
        if(m_stateAccumeTime > 1)
        {
            m_gameStatus = Playing;
            m_stateAccumeTime = 0;
        }
        G_RendDriver->ShaderColor4f(0, 1, 0, 1);
        if(m_tipMoves.size() != 0)
        {
            //取得需特殊显示牌信息
            Every* List1	=	&m_cardEverys[m_tipMoves.at(3 * m_curTip)];			//得到当前列数
            Every* List2	=	&m_cardEverys[m_tipMoves.at(3 * m_curTip + 1)];		//得到对比列数
			int moveNum	=	m_tipMoves.at(3 * m_curTip + 2);
            int count1	=	List1->m_cards.size();							//计算当前列元素个数
            //特殊显示主列牌
            for(int i = 0; i <= moveNum - 1; i++)
            {
                int val = List1->CardAt(count1 - moveNum + i);
                m_texCards[Value2CardID(val)]->Bind();
                G_RendDriver->DrawTextureRect(List1->CardRect(count1 - moveNum + i));
            }
            //特殊显示对比列牌
			int count2	=	List2->m_cards.size();						//计算对比列元素个数
            if (count2>0)
            {
				int val = List2->CardAt(count2 - 1);
				m_texCards[Value2CardID(val)]->Bind();
            }
			else
			{
				m_texCardSlot->Bind();
			}
            G_RendDriver->DrawTextureRect(List2->CardRect(count2 - 1));
        }
        G_RendDriver->ShaderColor4f(1, 1, 1, 1);
    }
    if(m_gameStatus == Dealing)
    {
        if(m_curDealEvery->m_index >= EveryNum-1)
        {
            m_gameStatus = Playing;
            m_stateAccumeTime = 0;
            DebugCheck();
            //发牌次数减少一
            m_dealLeft--;
            //判断完整列
            for(int i = 0; i < EveryNum; i++)
            {
                IsCardAccess(&m_cardEverys[i]);
            }
            //清除撤销
            m_curUndo	=	0;
        }
        else
        {
            vec2 oldPoint = m_curDealPoint;
            vec2 dif = m_curDealPointEnd - m_curDealPoint;
            dif.Normalize();
            m_curDealPoint += dif * (G_Timer->GetStepTimeLimited() * 2800);
            if((m_curDealPointEnd - m_curDealPoint).Dot(dif) <= 0)
            {
                m_curDealPoint.x = BoardRect2D.width - EveryDis - (m_dealLeft - 1) * CARDDIS_BACK - CardWidth;
                m_curDealPoint.y = DOWNPOS - CardHeight;
                m_curDealPointEnd = m_curDealEvery->CardRect(m_curDealEvery->m_cards.size()).GetPos();
                //加入发的牌
                m_curDealEvery->PushCard(m_cardsDealLeft.back());
                m_cardsDealLeft.pop_back();

                m_sound->PlaySound__("data/sound/poker/deal.wav");
                m_curDealEvery++;
                if(m_cardsDealLeft.size() > 0)
                {
                    m_curDealCardVal = m_cardsDealLeft.back();
                }
                else
                {
                    m_gameStatus = Playing;
                    m_stateAccumeTime = 0;
                    m_dealLeft = 0;
                    //判断完整列
                    for(int i = 0; i < EveryNum; i++)
                    {
                        IsCardAccess(&m_cardEverys[i]);
                    }
                    //清除撤销
                    m_curUndo	=	0;
                }
            }
            m_texCards[Value2CardID(m_curDealCardVal)]->Bind();
            G_RendDriver->DrawTextureRect(RectF(m_curDealPoint.x, m_curDealPoint.y, CardWidth, CardHeight));
        }
    }
    if(m_gameStatus == Completing)
    {
        vec2 oldPoint = m_curCompletePoint;
        vec2 dif = m_curCompletePointEnd - m_curCompletePoint;
        dif.Normalize();
        m_curCompletePoint += dif * (G_Timer->GetStepTimeLimited() * 2800);
        if((m_curCompletePointEnd - m_curCompletePoint).Dot(dif) <= 0)
        {
            m_curCompleteCardNum++;
            //收完
            if(m_curCompleteCardNum >= 13)
            {
                m_moveComplete	+=	1;
                //更新已完成牌链表
                if(m_curCompleteCardVal <= 13)
                    m_cardsComplete.push_back(1);
                else
                    m_cardsComplete.push_back(-1);
                m_curCompleteEvery->m_maxMoveNum	-=	13;
                m_curUndo	=	0;
                m_gameStatus = Playing;
                m_stateAccumeTime = 0;
                //收完翻牌
                if(m_curCompleteEvery->m_cards.size() == m_curCompleteEvery->m_backNum
                        && m_curCompleteEvery->m_backNum > 0)
                {
                    m_curCompleteEvery->m_backNum--;
                    m_curCompleteEvery->m_maxMoveNum = 1;
                }
            }
            else
            {
                m_sound->PlaySound__("data/sound/poker/deal.wav");
                m_curCompleteCardVal = m_curCompleteEvery->m_cards.back();
                //删除最后一张牌
                m_curCompleteEvery->m_cards.pop_back();
                //计算发牌的起点和终点位置
                int nCount	=	m_curCompleteEvery->m_cards.size();
                int nBack	=	m_curCompleteEvery->m_backNum;
                m_curCompletePoint	=	m_curCompleteEvery->CardRect(m_curCompleteEvery->m_cards.size()).GetPos();
            }
        }
        m_texCards[Value2CardID(m_curCompleteCardVal)]->Bind();
        G_RendDriver->DrawTextureRect(RectF(m_curCompletePoint.x, m_curCompletePoint.y, CardWidth, CardHeight));
        //绘制已经收好的
        if(m_curCompleteCardNum > 0)
        {
            m_texCards[Value2CardID(m_curCompleteCardVal - 1)]->Bind();
            G_RendDriver->DrawTextureRect(RectF(m_curCompletePointEnd.x, m_curCompletePointEnd.y, CardWidth, CardHeight));
        }
    }
    if(m_3dMode)
    {
        G_RendDriver->PopMatrix();
    }
    return true;
}



//发牌
bool MiniGameSpiderPoker::OnDeal()
{
    if(m_cardsDealLeft.size() <= 0)
    {
        return false;
    }
    m_gameStatus = Dealing;
    m_stateAccumeTime = 0;
    m_curDealEvery = m_cardEverys;
    //发牌的起点和终点
    m_curDealPoint.x = BoardRect2D.width - EveryDis - (m_dealLeft - 1) * CARDDIS_BACK - CardWidth;
    m_curDealPoint.y = DOWNPOS - CardHeight;
    m_curDealPointEnd = m_curDealEvery->CardRect(m_curDealEvery->m_cards.size()).GetPos();
    return true;
}


//得到每一列牌的可以相应鼠标消息的区域大小
void MiniGameSpiderPoker::GetRecvRect(Every*every, RectF &rect)
{
	int nCount		=	every->m_cards.size();
	int maxMove	=	every->m_maxMoveNum;
	int nBack	=	every->m_backNum;
	rect  = every->CardRect(every->m_backNum);
    rect.height	= CardHeight + (maxMove - 1) * CARDDIS_FRONT;
}

//判断拖动的牌的个数
int  MiniGameSpiderPoker::GetMoveCardNum(Every*every, const vec2& point)
{
    int nCount		=	every->m_cards.size();
    int maxMove	=	every->m_maxMoveNum;
    int nBack		=	every->m_backNum;
    if(nCount == 0)
        return 0;
    //定义可以移动的矩形最大范围
    RectF rect;
    for(int i = 0; i < maxMove; i++)
    {
        rect =	every->CardRect(nCount - i - 1);
        if(i == 0)		//如果鼠标左键点下位置在最上面一张牌上
        {
			rect.height	= CardHeight;
		}	
		else
		{
			rect.height	= CARDDIS_FRONT;
		}

        if(rect.IsPointIn(point))
            return i + 1;
    }
    return 0;
}



//计算鼠标点和拖动牌左上角坐标的距离
void MiniGameSpiderPoker::GetTwoPointJL(Every*every, const vec2& point)
{
	int nCount		=	every->m_cards.size();
	int maxMove	=	every->m_maxMoveNum;
    RectF rect;
    for(int i = 0; i < maxMove; i++)
    {
        rect = every->CardRect(nCount - maxMove + i);
        if(maxMove == i)
        {
            rect.height	= CardHeight;
        }
        else
        {
            rect.height	= CARDDIS_FRONT;
        }
        if(rect.IsPointIn(point))
        {
            m_moveOffset.x	=	point.x - rect.x;
            m_moveOffset.y	=	point.y - rect.y;
            return;
        }
    }
}



bool MiniGameSpiderPoker::OnTip()
{
    m_tipMoves.clear();
    //提示第一个
    //m_curTip	=	0;
    for(int i = 0; i < EveryNum; i++)
    {
        int nCount		=	m_cardEverys[i].m_cards.size();
        int nMoveCard	=	m_cardEverys[i].m_maxMoveNum;
        if(nCount == 0)
            continue;
        int	nCountOther	=	0;
        for(int n = 1; n <= nMoveCard; n++)	//对选定列每张可移动牌进行判断
        {
            for(int j = 0; j < EveryNum; j++)		//对选定牌与其他列最后一张牌进行对比
            {
                nCountOther	= m_cardEverys[j].m_cards.size();
                if(j == i || nCountOther == 0)
                    continue;
                //如果可移动牌可以移动,依次加入当前列,对比列,当前列与对比列可以移动牌的个数
                int ij = m_cardEverys[i].CardAt(nCount - n);
                int kc = m_cardEverys[j].CardAt(nCountOther - 1);
                if((ij ==  kc - 1
                        || ij == kc - 1 - 13
                        || ij == kc - 1 + 13)
                        && ij != 13
                        && ij != 26)
                {
                    //如果提示牌前还有牌
                    if(nCount - n - 1 >= m_cardEverys[i].m_backNum)
                    {
                        int ij_ = m_cardEverys[i].CardAt(nCount - n - 1);
                        if(ij_ != kc
                                && ij_ != kc + 13
                                && ij_ != kc - 13)
                        {
                            m_tipMoves.push_back(i);
                            m_tipMoves.push_back(j);
                            m_tipMoves.push_back(n);
                        }
                    }
                    else
                    {
                        m_tipMoves.push_back(i);
                        m_tipMoves.push_back(j);
                        m_tipMoves.push_back(n);
                    }
                }
            }
        }
    }
    //如果保存有可移动信息
    if(m_tipMoves.size() != 0)
    {
        m_sound->PlaySound__("data/sound/poker/deal.wav");
        //更新显示信息数
        m_curTip += 1;
        if(m_curTip >= m_tipMoves.size() / 3)
            m_curTip	=	0;
        return true;
    }
    else
    {
        m_sound->PlaySound__("data/sound/poker/cannot.wav");
        return false;
    }
}


//撤消
void MiniGameSpiderPoker::OnUndo()
{
    if(m_curUndo == 0)
        return;
    else
    {
        char Lb	=	m_undos[m_curUndo].LbFrom;
        char LbTo	=	m_undos[m_curUndo].LbTo;
        char MoveCardNum	=	m_undos[m_curUndo].MoveCardNum;
        int nBackNum		=	m_undos[m_curUndo].nBackNum;
		Every* every = &m_cardEverys[Lb];
		Every* everyTo = &m_cardEverys[LbTo];
		int nCount	=	everyTo->m_cards.size();
        for(int i = 0; i < MoveCardNum; i++)
        {
            //接收列减去移动牌
            int CurrentMoveCard	=	everyTo->m_cards.at(nCount - MoveCardNum);
            everyTo->DeleteCard(nCount - MoveCardNum);
            //移出牌的列增加移动牌
            every->PushCard(CurrentMoveCard);
        }
        //重新设置发牌列的未翻牌数
        every->m_backNum	=	nBackNum;
        every->m_maxMoveNum   =	every->CalMaxMoveNum();
        m_curUndo--;
    }
}



//判断某一列牌是否可以收牌
void MiniGameSpiderPoker::IsCardAccess(Every*every)
{
	int nCount		=	every->m_cards.size();
	int maxMove	=	every->m_maxMoveNum;
	int nBack		=	every->m_backNum;

    if(nCount - nBack < 13)
        return;
    //定义一个数组,存储1---13数字
    int cardNum[13];
    for(int i = 0; i < 13; i++)
        cardNum[i]	=	i + 1;
    bool isCardFullRedT	=	true;
    //利用循环进行判断
    for(int i = nCount; i > nCount - 13; i--)
    {
        if(every->m_cards.at(i - 1) != cardNum[nCount - i])
        {
            isCardFullRedT	=	false;
            m_curCompleteEvery = every;
            break;
        }
    }
    for(int i = 0; i < 13; i++)
        cardNum[i]	=	i + 14;
    bool isCardFullBlackT	=	true;
    for(int i = nCount; i > nCount - 13; i--)
    {
        if(every->m_cards.at(i - 1) != cardNum[nCount - i])
        {
            isCardFullBlackT	=	false;
            m_curCompleteEvery = every;
            break;
        }
    }
    //收牌(1--13或14--26依次存在)
    if(isCardFullRedT || isCardFullBlackT)
    {
        m_curCompleteCardNum = 0;
        m_curCompleteCardVal = m_curCompleteEvery->m_cards.back();
        //将当前列最后一张牌删除
        m_curCompleteEvery->m_cards.pop_back();
        //计算发牌的起点和终点位置
        m_curCompletePoint	=	m_curCompleteEvery->CardRect(nCount).GetPos();
        m_curCompletePointEnd.x		=	BoardRect2D.x + EveryDis + m_moveComplete * CARDDIS_BACK;
        m_curCompletePointEnd.y		=	DOWNPOS - CardHeight;
        m_gameStatus = Completing;
        m_stateAccumeTime = 0;
        m_curUndo	=	0;
    }
}
bool MiniGameSpiderPoker::IsGameEnd()
{
    bool IsGameEnd	=	true;
    for(int i = 0; i < EveryNum; i++)
    {
        if(m_cardEverys[i].m_cards.size() != 0)
        {
            IsGameEnd	=	false;
            break;
        }
    }
    return IsGameEnd;
}

void MiniGameSpiderPoker::AddScreen(char LbFrom, char LbTo, char MoveCardNum, int BackNum)
{
    if(m_curUndo == m_MaxScreen)
    {
        for(int i = 1; i < m_MaxScreen; i++)		//第一个屏幕状态不变,做为一个标志
            m_undos[i]	=	m_undos[i + 1];
    }
    else
        m_curUndo++;
    m_undos[m_curUndo].LbFrom	=	LbFrom;
    m_undos[m_curUndo].LbTo	=	LbTo;
    m_undos[m_curUndo].MoveCardNum	=	MoveCardNum;
    m_undos[m_curUndo].nBackNum		=	BackNum;
}



int  Every::CalMaxMoveNum()
{
	int cardNum	=	m_cards.size();
	for(int i = 1; i < cardNum - m_backNum + 1; i++)
	{
		if(IsLessThenTop(cardNum - i) || cardNum == 0)
			continue;
		else
		{
			m_maxMoveNum = i;
			return i;
		}
	}
	m_maxMoveNum = 0;
	return 0;
}

bool Every::IsLessThenTop(int index)
{
	if(index <= m_backNum || (index+1) > m_cards.size())
		return false;
	//如果当前牌比上一张牌小,并且当前牌数不是13,或者这张牌是最后一张牌
	if((m_cards.at(index) == m_cards.at(index - 1) - 1)
		&& (m_cards.at(index) != 13) || index == 0)
		return true;
	else
		return false;
}

void Every::DeleteCard(int index)
{
	if(index < 0 || index > m_cards.size() - 1)
		return;
	m_cards.erase(m_cards.begin() + index);
	CalMaxMoveNum();
}

void Every::PushCard(int card)
{
	m_cards.push_back(card);
	CalMaxMoveNum();
}

int  Every::CardAt(int Index)
{
	return m_cards[Index];
}

RectF Every::CardRect(int index)
{
	RectF rect;
	rect. x = G_SpiderGame->BoardRect2D.x + G_SpiderGame->EveryDis*(m_index + 1) + CardWidth * m_index;

	if (index < m_backNum)
	{
		//未翻的牌
		rect.y = G_SpiderGame->BoardRect2D.y+30 + index * CARDDIS_BACK;
	}
	else
	{
		//翻开的牌
		rect.y = G_SpiderGame->BoardRect2D.y+30 + m_backNum * CARDDIS_BACK + (index-m_backNum) * CARDDIS_FRONT;
	}

	rect.width  = CardWidth;
	rect.height = CardHeight;
	return rect;
}

完 

;