联机棋类游戏《憋尿罐》实现源码

      自己写的一个棋类小游戏,支持3D和2D显示,支持联机对弈和ai对弈。这是上小学时经常玩的一个小游戏,不知道叫什么名字,我们那叫“憋尿罐”。分为两个阶段,前期可以用 ‘顶’、‘夹‘、’挑’ 来吃棋子,后期只剩一个棋子时有点像民间游戏围虎棋,将最后一个棋子围入‘尿罐’即胜利。

 

 棋类游戏的ai算法一般使用Minimax极小化极大算法。

Minimax极小化极大算法:

用p代表棋局的某一状态,f(p)为棋局的评分函数,对我方越有利评分越大,对对方越有利评分越低。minimax(p,depth)为估值函数。

基本思想

(1)当轮到对手走步时,考虑最坏的情况(即f(p)取极小值)

(2)当轮到我方走步时,考虑最好的情况(即f(p)取极大值)

(3)交替使用(1)和(2)两种方法传递倒推值。

假设某棋局推演4步的状态树如下:
先给末端状态评分

 从第4步往上反推极大值,第3步我方所能得到的分数是第4步中最差的(因为下一步对手总是会选择对我方最不利的极小值)。

从第3步往上反推极小值,第2步对方所能得到的分数是第3步中最高的(因为下一步我方总是会选择对我方最有利的极大值)。

伪代码:A表示己方,B表示对方
int MiniMax(int level, int p)
{
    if (level == 0) 
        return f(p);//局面的评分

    int best;
    if(player == A)
    {
        best = INT_MIN; 
        while(sub) //子树不空
        {
            best = max(best, MiniMax(level-1,sub)); //取更高分给己方
            next sub;
        }
    }
    else    //player == B
    {
        best = INT_MAX; 
        while(sub) //子树不空
        {
            best = min(best, MiniMax(level-1,sub)); //取更低分给对方
            next sub;
        }
    }
    return best;
}

α-β剪枝算法:

最小最大值算法遍历所有的子树,效率较低,一般会用α-β剪枝算法优化。对于alpha-beta剪枝算法,还需要配合排序,优先搜索最好的走法,增加剪枝的效率。

α代表下界,β代表上界,在(α,β)的范围内进行搜索,初始值(α,β)= (-∞,+∞)
(1)对手B负责更新上限,目的是使上限尽可能的小,留给 player A最不利的局面。
(2)己方A负责更新下限,目的是使下限尽可能的大,保证最次的情况下也可以提高分数,留给自己最好的局面

    进行深度优先搜索,当生成结点到达规定深度时,立即进行静态估计,一旦某一个非端点的节点可以确定倒推值的时候立即赋值,节省下其他分支拓展到节点的开销。

剪枝规则:
(1)α剪枝,任一极小层节点的β值不大于他任一前驱极大值层节点的α值,即α(前驱层)≥β(后继层),则可以终止该极小层中这个MIN节点以下的搜索过程。这个MIN节点的倒推值确定为这个β值。
(2)β剪枝,任一极大层节点的α值不小于它任一前驱极小值层节点的β值,即β(前驱层)≤α(后继层),则可以终止该极大值层中这个MAX节点以下的搜索过程。这个MAX节点的倒推值确定为这个α值。

 

伪代码: 

int AlphaBeta(int level,State p,int alpha,int beta,char player=='A')
{
    if (level == 0 || no sub) 
        return f(p);//局面的评分

    int best;
    if(player == 'A')
    {
        best = INT_MIN; 
        while(sub) //子树不空
        {
            best  = max(best, AlphaBeta(level-1,sub,alpha,beta,'B')); //A取更高分给A
            alpha = max(alpha,best);
            if(beta < alpha)     //beta裁剪,B的下一步使A获得的分数更高 => 剪枝(B不会选这个节点)
                break;
            next sub;
        }
    }
    else//player == B
    {
        best = INT_MAX; 
        while(sub) //子树不空
        {
            best = min(best, AlphaBeta(level-1,sub,alpha,beta,'A')); //B取更低分给A
            beta = min(beta,best);
            if( beta < alpha) //alpha裁剪
                break;
            next sub;
        }
    }
    return best;
}
//初始调用
AlphaBeta(depth,p,INT_MIN,INT_MAX,'A');

其它比如评分函数 直接见源码:

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Urinal/MiniGameUrinal.h
//  @Brief:     MiniGameUrinal
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#ifndef  __MiniGameUrinal__H__
#define  __MiniGameUrinal__H__

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

//
enum ManSide
{
	SideNull = -1,
	SideRed=0,			    //红方
	SideBlack=1,			//黑方
};
 
enum MiniUrinalCmd
{
	CMD_ManMove ,      //棋子走动
	CMD_ManPass ,      //棋子走动
	CMD_GameOver,
	CMD_Restart ,
};
const char* UrinalCmdToString(int enumeration);

namespace RendSys
{
	class MC_Frame;
}
class UrinalPlayerRole;
class MiniGameUrinal:public MiniGame
{
public:
	//棋子移动方向
	enum Dir
	{
		UP   =0,
		DOWN ,
		LEFT ,
		RIGHT,
		UPLEFT,
		UPRIGHT,
		DOWNLEFT,
		DOWNRIGHT,
	};
	//交叉点
	class Block
	{
	public:
		int    id;        //index
		vec2I  pos;       //棋子位置(格子)
		vec2I  pixelPos;  //屏幕位置
		int    man;       //棋子
		Block* neighbour[8];//邻居
		int    flag;
	};

	MiniGameUrinal();
	virtual ~MiniGameUrinal();

	virtual bool KeepResource(bool once,int& circle,String& nextTip);
	virtual bool Start();
	virtual bool Stop();
	virtual bool Render();
	virtual void RenderUI();
	virtual bool Update();
	virtual bool Free();
	virtual bool IsEnd();

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

	void OnLButtonDown(const vec2I& pos);

	//坐标转换
	bool ScreenToBlock(const vec2I &pos,Block **block);
	bool BlockToScreen(Block *block,vec2I &pos);

	bool WorldToBlock(const vec3  &pos,Block **block);
	bool BlockToWorld(Block *block,vec3 &pos);

	bool CanGo (int from,int to);
	bool SendGo(int from,int to);
	bool TryGo (int from,int to);
	//弃手
	bool Pass();
	bool SendPass();
	//吃子
	bool CheckFlip(Block* blockMap,int to);
	//计数
	int  Count(Block* blockMap,int side);
	//获得老虎位置
	Block* Tiger(Block* blockMap);

	//主思考函数
	bool UrinalThink(int side,int &resFrom, int &resTo);
	//评分函数
	int  Envalue(Block* blockMap,int side);
	//AlphaBeta剪枝的minimax极小极大算法
	int  AlphaBeta(Block* blockMap,int depth,int alpha,int beta,ManSide side,vec2I& resOP,bool minmax =true,bool first=true);
	//搜集所有可能的走法
	void Search(Block* blockMap,int side,void* opList);
	//根据初状态及走法构造子状态
	void MakeSub(Block* blockMap,Block* subMap,vec2I& op);
	//拓扑邻居
	void MakeNeighbour(Block* blockMap,Block* subMap);

	UrinalPlayer* GetTurnPlayer();	

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



//private:
#define BlockNum 29
	Block m_blocks[BlockNum];//旗子图
	int   m_curSide;
	Block* m_fromPoint;//
	Block* m_toPoint;//


	vec2I Offset;//左上角	
	TexturePtr m_textureMan[2];	//2种图标
	TexturePtr m_textureFrom;	
	TexturePtr m_textureSelectGreen;	
	TexturePtr m_textureSelectRed;
	TexturePtr m_textureBoard;
	TexturePtr m_textureCantgo;
	TexturePtr m_thinkTexture[4];


	//
	MC_Frame*  m_movieMan[2];
	MC_Frame*  m_movieCannot;
	MC_Frame*  m_movieFrom;
	MC_Frame*  m_movieSelectRed;
	MC_Frame*  m_movieSelectGreen;
	MC_Frame*  m_movieBoard;

	MovieClip* m_movieThink;

	UrinalPlayerRole* m_myRolePlayer;
	//非观战时 viewside==myside
	int              m_myViewSide;
		

};
extern MiniGameUrinal* G_UrinalGame;
#endif 

//========================================================
//  @Date:     2016.05
//  @File:     SourceDemoClient/Urinal/MiniGameUrinal.cpp
//  @Brief:     MiniGameUrinal
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#include "General/Pch.h"
#include "General/Window.h"
#include "General/Timer.h"
#include "Gui/GuiMgr.h"
#include "Gui/RpgGuis.h"
#include "Input/InputMgr.h"
#include "Urinal/UrinalPlayer.h"
#include "Urinal/MiniGameUrinal.h"
#include "Urinal/MiUrinal_PlayGui.h"
#include "Render/RendDriver.h"
#include "Render/Shader.h"
#include "Render/MC_Misc.h"
#include "Rpg/SyncGameInfo.h"
#include "Packet/PacketMiniGame.h"
//#include "Rpg/MiniGame.h"
#include "Net/PacketList.h"
#include "General/Pce.h"
#include "Render/Camera.h"

const int ManWidth2D = 35;		         //棋格宽度
const int GameRectWidth2D     = 512;  //棋盘的长宽, 
const int BoardHeight2D       = 317; 

static float BoardCellWidth3D = 7.12f;		         //棋格宽度
static float BoardWidth3D     = 64;  //棋盘的长宽, 
static float BoardHeight3D    = 36; 

static int ThinkDepth = 3;  //思考的步数


//棋子类型
    
const char* UrinalCmdToString(int enumeration)
{
	switch(enumeration)
	{
	case CMD_ManMove :return "CMD_ManMove ";		
	case CMD_GameOver:return "CMD_GameOver";		
	case CMD_Restart :return "CMD_Restart ";			
	default             :return "CMD_unknow";
	}
	return "CMD_unknow";
}

static int opDir[] =
{
	MiniGameUrinal::DOWN,//UP ,
	MiniGameUrinal::UP,//DOWN ,
	MiniGameUrinal::RIGHT,//LEFT ,
	MiniGameUrinal::LEFT,//RIGHT,
	MiniGameUrinal::DOWNRIGHT,//UPLEFT,
	MiniGameUrinal::DOWNLEFT,//UPRIGHT,
	MiniGameUrinal::UPRIGHT,//DOWNLEFT,
	MiniGameUrinal::UPLEFT,//DOWNRIGHT,
};

MiniGameUrinal* G_UrinalGame;
MiniGameUrinal::MiniGameUrinal()
:m_movieThink(NULL)
{
	G_UrinalGame = this;
	CmdEnumToString = UrinalCmdToString;
}

MiniGameUrinal::~MiniGameUrinal()
{
	G_UrinalGame = NULL;
}

bool MiniGameUrinal::Start()
{
	m_myRolePlayer = NULL;
	if(!MiniGame::Start())
		return false;

	for(int i=0;i<BlockNum;++i)
	{
		m_blocks[i].id  = i;
		m_blocks[i].man  = SideNull;
		for(int d=0;d<8;++d)
		{
			m_blocks[i].neighbour[d] = NULL;
		}
	}
	for(int i=0;i<25;++i)
	{
		m_blocks[i].pos = vec2I(i/5,i%5);
	}
	m_blocks[25].pos = vec2I(5,1);
	m_blocks[26].pos = vec2I(5,2);
	m_blocks[27].pos = vec2I(5,3);
	m_blocks[28].pos = vec2I(6,2);//尿罐

	m_blocks[ 0].pixelPos = vec2I(16,50);
	m_blocks[ 1].pixelPos = vec2I(23,109);
	m_blocks[ 2].pixelPos = vec2I(30,164);
	m_blocks[ 3].pixelPos = vec2I(32,228);
	m_blocks[ 4].pixelPos = vec2I(38,288);
	m_blocks[ 5].pixelPos = vec2I(67,47);
	m_blocks[ 6].pixelPos = vec2I(78,110);
	m_blocks[ 7].pixelPos = vec2I(87,165);
	m_blocks[ 8].pixelPos = vec2I(90,229);
	m_blocks[ 9].pixelPos = vec2I(89,285);
	m_blocks[10].pixelPos = vec2I(139,39);
	m_blocks[11].pixelPos = vec2I(144,106);
	m_blocks[12].pixelPos = vec2I(146,164);
	m_blocks[13].pixelPos = vec2I(154,223);
	m_blocks[14].pixelPos = vec2I(154,283);
	m_blocks[15].pixelPos = vec2I(213,38);
	m_blocks[16].pixelPos = vec2I(215,98);
	m_blocks[17].pixelPos = vec2I(215,163);
	m_blocks[18].pixelPos = vec2I(215,220);
	m_blocks[19].pixelPos = vec2I(217,282);	
	m_blocks[20].pixelPos = vec2I(279,34);
	m_blocks[21].pixelPos = vec2I(283,93);
	m_blocks[22].pixelPos = vec2I(288,158);
	m_blocks[23].pixelPos = vec2I(292,220);
	m_blocks[24].pixelPos = vec2I(295,280);
	m_blocks[25].pixelPos = vec2I(350,95);
	m_blocks[26].pixelPos = vec2I(361,159);
	m_blocks[27].pixelPos = vec2I(370,219);
	m_blocks[28].pixelPos = vec2I(455,149);


	for(int i=0;i<5;++i)
	{
		m_blocks[0+i*5].man = SideRed;
		m_blocks[4+i*5].man = SideBlack;
	}

	Block* block = m_blocks;
	for(int x=0;x<5;++x)
	{
		for(int y=0;y<5;++y,++block)
		{
			if(x>0) block->neighbour[LEFT] = block-5;
			if(x<4) block->neighbour[RIGHT] = block+5;
			if(y>0) block->neighbour[DOWN] = block-1;
			if(y<4) block->neighbour[UP] = block+1;

			//有些格子不能走斜线
			if((x+y)%2==0)
			{
				if(x>0 && y>0) block->neighbour[DOWNLEFT] = block-6;		
				if(x>0 && y<4) block->neighbour[UPLEFT] = block-4;
				if(x<4 && y>0) block->neighbour[DOWNRIGHT] = block+4;		
				if(x<4 && y<4) block->neighbour[UPRIGHT] = block+6;
			}
		}
	}
	//
	m_blocks[22].neighbour[DOWNRIGHT] = &m_blocks[25];
	m_blocks[22].neighbour[RIGHT]     = &m_blocks[26];
	m_blocks[22].neighbour[UPRIGHT]   = &m_blocks[27];

	m_blocks[25].neighbour[UPLEFT]    = &m_blocks[22];
	m_blocks[25].neighbour[UP]        = &m_blocks[26];
	m_blocks[25].neighbour[UPRIGHT]   = &m_blocks[28];

	m_blocks[26].neighbour[UP]        = &m_blocks[27];
	m_blocks[26].neighbour[DOWN]      = &m_blocks[25];
	m_blocks[26].neighbour[LEFT]      = &m_blocks[22];
	m_blocks[26].neighbour[RIGHT]     = &m_blocks[28];

	m_blocks[27].neighbour[DOWNLEFT]  = &m_blocks[22];
	m_blocks[27].neighbour[DOWN]      = &m_blocks[26];
	m_blocks[27].neighbour[DOWNRIGHT] = &m_blocks[28];

	m_blocks[28].neighbour[UPLEFT]    = &m_blocks[27];
	m_blocks[28].neighbour[LEFT ]     = &m_blocks[26];
	m_blocks[28].neighbour[DOWNLEFT]  = &m_blocks[25];


	//check
	for(int i=0;i<BlockNum;++i)
	{
		Block* block = &m_blocks[i];
		for(int d=0;d<8;++d)
		{
			if (block->neighbour[d]
			&& block->neighbour[d]->neighbour[opDir[d]] != block)
			{
				Assert(0,"MiniGameUrinal map not nodirected");
			}
		}
	}

	m_curSide=SideRed;

	m_fromPoint = NULL;
	m_toPoint   = NULL;

	if (m_movieScene)
	{
		Frame frame;
		frame.SetPos(m_startPos);
		m_movieScene->SetProgramFrame(&frame);
		m_movieScene->Advance();
	}

	m_gameState  = MS_Gamming;
	m_myViewSide = SideBlack;

	//
	for(int i = 0; i < m_allPlayerNum; i++)
	{
		dynamic_cast<UrinalPlayer*>(m_miniPlayer[i])->m_side = i==0?SideRed:SideBlack;
		//dynamic_cast<UrinalPlayer*>(m_miniPlayer[i])->m_side = i==0?SideBlack:SideRed;
	}


	if(m_myRolePlayer)
		m_myViewSide = m_myRolePlayer->m_side; 

	//进入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* MiniGameUrinal::CreatePlayer()
{
	return new UrinalPlayer;
}

MiniPlayer* MiniGameUrinal::CreateRobot()
{
	return new UrinalPlayerRobot;
}

MiniPlayer* MiniGameUrinal::CreateRole()
{
	m_myRolePlayer = new UrinalPlayerRole;
	return m_myRolePlayer;
}


bool MiniGameUrinal::Stop()
{
	G_Camera->PopCtrler();
	//CameraCtrlerTarget* ctrlerTarget = G_Camera->IsCurCtrler<CameraCtrlerTarget>();
	//if(ctrlerTarget)
	//	ctrlerTarget->SetTarEntity(G_MyRole);

	{
		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 MiniGameUrinal::SendGo(int from,int to)
{
	C2SPacketMiniGameCmd packet;
	packet.WriteHeader();
	packet.WriteValue(CMD_ManMove);  
	packet.WriteValue(from); 
	packet.WriteValue(to); 
	G_MiniGame->SendPacketToOther(&packet);
	return true;
}

bool MiniGameUrinal::TryGo(int from,int to)
{
	if(!CanGo(from,to))
	{
		PlaySound__("data/sound/poker/cannot.wav");
		return false;
	}

	m_blocks[to].man = m_blocks[from].man;
	m_blocks[from].man = SideNull;

	if(CheckFlip(m_blocks,to))
	{
		//吃子
		PlaySound__("data/sound/ui_click.wav");
	}
	else
	{
		PlaySound__("data/sound/billiards/shoot.wav");
	}

	m_fromPoint = &m_blocks[from];
	m_toPoint = &m_blocks[to];

	GetTurnPlayer()->m_manSelected = to;
	m_turnTime = 0;

	//换手
	m_curSide=!m_curSide;
	GetTurnPlayer()->m_manSelected=-1;
	return true;
}


bool MiniGameUrinal::Pass()
{
	PlaySound__("data/sound/poker/cannot.wav");

	m_turnTime = 0;

	//换手
	m_curSide=!m_curSide;
	GetTurnPlayer()->m_manSelected=-1;
	return true;
}
bool MiniGameUrinal::SendPass()
{
	C2SPacketMiniGameCmd packet;
	packet.WriteHeader();
	packet.WriteValue(CMD_ManPass);  
	G_MiniGame->SendPacketToOther(&packet);
	return true;
}

UrinalPlayer* MiniGameUrinal::GetTurnPlayer()
{
	//return dynamic_cast<UrinalPlayer*>(m_miniPlayer[m_curSide]);
	for(int i = 0; i < m_allPlayerNum; i++)
	{
		UrinalPlayer* player = dynamic_cast<UrinalPlayer*>(m_miniPlayer[i]);
		if (player->m_side == m_curSide)
		{
			return player;
		}
	}
	return NULL;
}

bool MiniGameUrinal::ScreenToBlock(const vec2I &pos,Block **block)
{
	*block = NULL;
	vec2I point = pos - Offset;
	for(int i=0;i<BlockNum;++i)
	{
		if ((point-m_blocks[i].pixelPos).Length()<ManWidth2D/2.2f)
		{
			*block = &m_blocks[i];
			return true;
		}
	}
	return false;
}

bool MiniGameUrinal::BlockToScreen(Block *block,vec2I &pos)
{
	pos = block->pixelPos;
	pos += Offset - vec2I(ManWidth2D/2,ManWidth2D/2);
	return true;
}

bool MiniGameUrinal::WorldToBlock(const vec3 &pos_,Block **block)
{
	vec3 pos = pos_ - m_startPos;
	pos.x = pos.x + BoardWidth3D/2;
	pos.z = pos.z + BoardHeight3D/2;
	pos.x /= BoardWidth3D;
	pos.y /= BoardHeight3D;
	pos.x *= m_textureBoard->GetWidth();
	pos.y *= m_textureBoard->GetHeight();

	return ScreenToBlock(vec2I(pos.x,pos.y),block);
}

bool MiniGameUrinal::BlockToWorld(Block *block,vec3 &pos_)
{
	if (block==NULL)
	{
		return false;
	}
	float x = float(block->pixelPos.x)/m_textureBoard->GetWidth();
	float y = float(block->pixelPos.y)/m_textureBoard->GetHeight();

	pos_.x = x*BoardWidth3D - BoardWidth3D/2 ;
	pos_.z = y*BoardHeight3D - BoardHeight3D/2 ;
	pos_.y = 10;
	pos_ += m_startPos;
	return true;
}

bool MiniGameUrinal::CanGo(int from,int to)
{
	if (from<0||from>=BlockNum
		||to<0||to>=BlockNum
		||from==to)
	{
		return false;
	}
	Block* fromBlock = &m_blocks[from];
	Block* toBlock = &m_blocks[to];

	//cur turn
	if(fromBlock->man!=m_curSide)
	{
		return false;
	}

	//米子移动
	vec2I dif = toBlock->pos - fromBlock->pos;
	int dir = -1;
	if (dif.x==0 && dif.y<0) dir = DOWN;
	else if(dif.x==0 && dif.y>0) dir = UP;
	else if(dif.y==0 && dif.x<0) dir = LEFT;
	else if(dif.y==0 && dif.x>0) dir = RIGHT;
	else if(dif.y>0 && dif.x<0) dir = UPLEFT;
	else if(dif.y>0 && dif.x>0) dir = UPRIGHT;
	else if(dif.y<0 && dif.x<0) dir = DOWNLEFT;
	else if(dif.y<0 && dif.x>0) dir = DOWNRIGHT;

	if(dir==-1)
	{
		return false;
	}

	int step = max(abs(dif.x),abs(dif.y)); 
	Block* block = fromBlock;
	//路线上是否有棋子:
	for(int i=0;i<step;++i)
	{
		block = block->neighbour[dir];
		if(block==NULL)
		{
			return false;
		}
		if(block==NULL || block->man!=SideNull)
		{
			return false;
		}
	}

	return true;	
}

bool MiniGameUrinal::KeepResource(bool once,int& circle,String& nextTip)
{
	G_TextureMgr->AddTexture(m_textureMan[0],"data/minigame/urinal/redman.png");
	G_TextureMgr->AddTexture(m_textureMan[1],"data/minigame/urinal/blackman.png");
	G_TextureMgr->AddTexture(m_textureFrom,"data/minigame/urinal/from.png");
	G_TextureMgr->AddTexture(m_textureSelectGreen,"data/minigame/urinal/select.png");
	G_TextureMgr->AddTexture(m_textureSelectRed,"data/minigame/urinal/select2.png");

	G_TextureMgr->AddTexture(m_textureBoard,"data/minigame/urinal/board.png");
	G_TextureMgr->AddTexture(m_textureCantgo,"data/minigame/urinal/cantgo.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");

	//
	char buf[256];
	if (m_movieScene == NULL)
	{
		LoadConfig loader(LoadConfig::GenDonotReShrinkBound, true, true);
		m_movieScene = new RendSys::MovieClip;
		m_movieScene->LoadFromFile("data/minigame/urinal/urinal.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;
	}
	for (int i=0;i<2;i++)
	{
		sprintf(buf,"man%02d",i);
		m_movieMan[i] = dynamic_cast<MC_Frame*>(m_movieScene->GetMovieClip(buf));
	}
	m_movieCannot = dynamic_cast<MC_Frame*>(m_movieScene->GetMovieClip("cannot"));
	m_movieFrom   = dynamic_cast<MC_Frame*>(m_movieScene->GetMovieClip("select0"));
	m_movieSelectRed = dynamic_cast<MC_Frame*>(m_movieScene->GetMovieClip("select1"));
	m_movieSelectGreen = dynamic_cast<MC_Frame*>(m_movieScene->GetMovieClip("select2"));
	m_movieFrom->ZeroFrames();

	m_movieBoard = dynamic_cast<MC_Frame*>(m_movieScene->GetMovieClip("board"));

	if (m_movieThink == NULL)
	{
		LoadConfig loader(LoadConfig::GenDonotReShrinkBound, true, true);
		m_movieThink = new RendSys::MovieClip;
		m_movieThink->LoadFromFile("data/minigame/poker/think.movie", &loader);
	}
	return true;
}



void MiniGameUrinal::OnLButtonDown(const vec2I& pos) 
{
	if (m_myRolePlayer && m_curSide == m_myRolePlayer->m_side)
	{
		Block* block;
		if (m_3dMode)
		{
			
			vec3 dir;
			vec3 start;
			G_Camera->GetMouseTray(start,dir);
			RayMovieCollideRes res;
			res.vStart = start;
			res.vEnd = start+PICKLEN*dir;
			res.justBond = false;
			if(m_movieBoard->IntersectTray(res))
			{
				if(WorldToBlock(res.resPos,&block))
				{
					if(block->man==m_myRolePlayer->m_side)
					{
						m_myRolePlayer->m_manSelected = block->id;
					}
					else if(m_myRolePlayer->m_manSelected!=-1)
					{
						int man = m_myRolePlayer->m_manSelected;
						if(TryGo(man,block->id))
							SendGo(man,block->id);
					}
				}
			}

		}
		else
		{
		
			if(ScreenToBlock(pos,&block))
			{
				if(block->man==m_myRolePlayer->m_side)
				{
					m_myRolePlayer->m_manSelected= block->id;
				}
				else if(m_myRolePlayer->m_manSelected!=-1)
				{
					int man = m_myRolePlayer->m_manSelected;
					if(TryGo(man,block->id))
						SendGo(man,block->id);
				}

			}
		}
	}
	
}

bool MiniGameUrinal::Render()
{
	if (m_3dMode)
	{
		if(m_movieScene==NULL
			||m_movieScene->IsLoadComplete()==false)
			return false;

		G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,true);
		m_movieScene->RendClip();
		m_movieThink->RendClip();

		MC_Frame* frameMovie = NULL;
		//棋子
		mat4 trans;
		mat4 scale;
		Block* block;
		vec3 pos;
		for(int i=0;i<BlockNum;i++)
		{
				block = &m_blocks[i];
				if(block->man!=SideNull)
				{
					BlockToWorld(block,pos);
					trans.FromTranslate(pos);
					G_RendDriver->PushMatrix();
					G_RendDriver->MultMatrix(trans);
					frameMovie = G_UrinalGame->m_movieMan[block->man==SideRed?0:1];
					frameMovie->BeginCommonRendState(NormalPass);
					frameMovie->GetMesh()->Render();
					frameMovie->EndCommonRendState();
					G_RendDriver->PopMatrix();
				}
		}

		//from
		if(m_fromPoint)
		{
			BlockToWorld(m_fromPoint,pos);
			trans.FromTranslate(pos);
			G_RendDriver->PushMatrix();
			G_RendDriver->MultMatrix(trans);
			frameMovie = G_UrinalGame->m_movieFrom;
			frameMovie->BeginCommonRendState(NormalPass);
			frameMovie->GetMesh()->Render();
			frameMovie->EndCommonRendState();
			G_RendDriver->PopMatrix();

			//Frame frame;
			//frame->SetPos(pos);
			//m_movieFrom->SetProgramFrame(&frame);
		}

		//to
		if (m_myRolePlayer
			&&m_curSide == m_myRolePlayer->m_side)
		{
			vec3 dir;
			vec3 start;
			G_Camera->GetMouseTray(start,dir);
			RayMovieCollideRes res;
			res.vStart = start;
			res.vEnd = start+PICKLEN*dir;
			res.justBond = false;
			if(m_movieBoard->IntersectTray(res))
			{
				//G_RendDriver->Color3f(1,1,1);
				//G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,false);
				//G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,false);
				//G_RendDriver->RendBegin(RS_POINTS);
				//G_RendDriver->Vertex3fv(&res.resPos.x);
				//G_RendDriver->RendEnd();
				//G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true);

				if(m_myRolePlayer->m_manSelected==-1)
				{
					//点选
					if(WorldToBlock(res.resPos,&block))
					{
						if (block->man==m_myRolePlayer->m_side)
						{
							//高亮放大棋子 可以选择
							BlockToWorld(block,pos);
							trans.FromTranslate(pos);
							scale.FromScale(1.2f,1.2f,1.2f);
							G_RendDriver->PushMatrix();
							G_RendDriver->MultMatrix(trans*scale);
							frameMovie = G_UrinalGame->m_movieMan[block->man==SideRed?0:1];
							frameMovie->BeginCommonRendState(NormalPass);
							frameMovie->GetMesh()->Render();
							frameMovie->EndCommonRendState();
							G_RendDriver->PopMatrix();
						}
					}
				}
				else
				{
					//落子
					Block* fromBlock = &m_blocks[m_myRolePlayer->m_manSelected];
	
					if(WorldToBlock(res.resPos,&block)==false
						||MiniGameUrinal::CanGo(fromBlock->id,block->id)==false)
					{
						//不可以落子
						BlockToWorld(block,pos);
						trans.FromTranslate(pos);
						G_RendDriver->PushMatrix();
						G_RendDriver->MultMatrix(trans);
						frameMovie = G_UrinalGame->m_movieCannot;
						frameMovie->BeginCommonRendState(NormalPass);
						frameMovie->GetMesh()->Render();
						frameMovie->EndCommonRendState();
						G_RendDriver->PopMatrix();
					}
					else
					{
						//拖拽棋子
						BlockToWorld(block,pos);
						int manID = fromBlock->man==SideRed?0:1;
						//pos = res.resPos;
						//pos.x -= BoardCellWidth3D/2;
						//pos.z -= BoardCellWidth3D/2;
						trans.FromTranslate(pos);
						scale.FromScale(0.9f,0.9f,0.9f);
						G_RendDriver->PushMatrix();
						G_RendDriver->MultMatrix(trans*scale);
						frameMovie = G_UrinalGame->m_movieMan[manID];
						frameMovie->BeginCommonRendState(NormalPass);
						frameMovie->GetMesh()->Render();
						frameMovie->EndCommonRendState();
						G_RendDriver->PopMatrix();
					}

				}
			}
		}

		//
		for(int i = 0; i < m_allPlayerNum; i++)
		{
			dynamic_cast<UrinalPlayer*>(m_miniPlayer[i])->Render();
		}

	}
	else
	{


		G_RendDriver->BeginUI();
		G_RendDriver->Color4f(1,1,1,1);
		G_RendDriver->SetRenderStateEnable(RS_BLEND,true);
		G_RendDriver->BlendFunc(Blend_Filter);
		G_ShaderMgr->PushShader();
		Texture* tex = m_textureBoard;
		tex->Bind();
		Offset.x = (G_Window->m_iWidth - GameRectWidth2D)/2;
		Offset.y = (G_Window->m_iHeight - BoardHeight2D)/2;
		G_RendDriver->DrawTextureRect(RectF(Offset.x,Offset.y,GameRectWidth2D,BoardHeight2D));

		//debug
		if(0)
		{
			G_RendDriver->Color3f(1,0,0);
			G_RendDriver->DisableRendState(RS_TEXTURE_2D);
			G_RendDriver->RendBegin(RS_LINES);
			for(int i=0;i<BlockNum;++i)
			{
				Block* block = &m_blocks[i];
				for(int d=0;d<8;++d)
				{
					Block* blockN = block->neighbour[d];
					if (blockN)
					{
						G_RendDriver->Vertex3f(block->pixelPos.x+Offset.x,G_Window->m_iHeight-(block->pixelPos.y+Offset.y),0);
						G_RendDriver->Vertex3f(blockN->pixelPos.x+Offset.x,G_Window->m_iHeight-(blockN->pixelPos.y+Offset.y),0);
					}
				}
			}
			G_RendDriver->RendEnd();
			G_RendDriver->Color3f(1,1,1);
			G_RendDriver->EnableRendState(RS_TEXTURE_2D);
		}

		//棋子
		Block* block;
		vec2I pos;
		for(int i=0;i<BlockNum;i++)
		{
				block = &m_blocks[i];
				if(block->man!=SideNull)
				{
					Texture* tex = m_textureMan[block->man];
					tex->Bind();
					BlockToScreen(block,pos);
					G_RendDriver->DrawTextureRect(RectF(pos.x,pos.y,ManWidth2D,ManWidth2D));
				}
		}

		//from
		if(m_fromPoint)
		{
			Texture* tex = m_textureFrom;
			tex->Bind();
			BlockToScreen(m_fromPoint,pos);
			G_RendDriver->DrawTextureRect(RectF(pos.x,pos.y,ManWidth2D,ManWidth2D));
		}

		//to
		if (m_myRolePlayer
			&&m_curSide == m_myRolePlayer->m_side)
		{
			pos.x = G_Mouse->GetMousePos().x;
			pos.y = G_Mouse->GetMousePos().y;

			if(m_myRolePlayer->m_manSelected==-1)
			{
				//点选
				if(ScreenToBlock(pos,&block)
					&&block->man==m_myRolePlayer->m_side)
				{
					//高亮棋子 可以选择
					Texture* tex = m_textureMan[block->man];
					tex->Bind();
					BlockToScreen(block,pos);
					G_RendDriver->DrawTextureRect(RectF(pos.x-2,pos.y-2,ManWidth2D+4,ManWidth2D+4));
				}
			}
			else
			{
				//落子
				Block* fromBlock = &m_blocks[m_myRolePlayer->m_manSelected];
				Texture* tex = m_textureMan[fromBlock->man];
				tex->Bind();
				G_RendDriver->Color4f(1,1,1,0.5f);
				G_RendDriver->DrawTextureRect(RectF(pos.x-ManWidth2D/2,pos.y-ManWidth2D/2,ManWidth2D,ManWidth2D));

				if(ScreenToBlock(pos,&block)==false
					||MiniGameUrinal::CanGo(fromBlock->id,block->id)==false)
				{
					//不可以落子
					m_textureCantgo->Bind();
					G_RendDriver->Color4f(1,1,1,0.5f);
					G_RendDriver->DrawTextureRect(RectF(pos.x,pos.y,ManWidth2D,ManWidth2D));
				}

				G_RendDriver->Color4f(1,1,1,1);
			}
		}

		for(int i = 0; i < m_allPlayerNum; i++)
		{
			dynamic_cast<UrinalPlayer*>(m_miniPlayer[i])->Render();
		}

		G_RendDriver->EndUI();
		G_ShaderMgr->PopShader();
	}

	return true;
}

void MiniGameUrinal::RenderUI()
{
	MiniGame::RenderUI();
}
bool MiniGameUrinal::Update()
{
	if (m_myRolePlayer==NULL)
	{
		//?todo 观战
		return false;
	}
	if(m_blocks[BlockNum-1].man!=SideNull)
	{
		G_GuiMgr->PopGui("MiUrinal_PlayGui");
		G_GuiMgr->GetGui<Rpg_ResultDialog>()->ShowResult(true);
		G_GuiMgr->PushGui("Rpg_ResultDialog",GL_DIALOGBOTTOM);
		m_gameState=MS_End;
		return true;
	}

	m_movieScene->Advance();
	m_movieThink->Advance();

	m_turnTime += G_Timer->GetStepTimeLimited();
	vec2I pos;
	pos.x = G_Mouse->GetMousePos().x;
	pos.y = G_Mouse->GetMousePos().y;

	//左键
	if (G_UrinalGame->IsButtonUping(MOUSE_LEFT))
	{
		OnLButtonDown(pos);
	}

	for(int i = 0; i < m_allPlayerNum; i++)
	{
		dynamic_cast<UrinalPlayer*>(m_miniPlayer[i])->Update();
	}
	return true;
}

bool MiniGameUrinal::Free()
{
	MiniGame::Free();
	if (m_movieThink)
	{
		m_movieThink->FreeMovie();
		delete m_movieThink;
		m_movieThink = NULL;
	}
	return true;
}

bool MiniGameUrinal::IsEnd()
{
	return m_gameState == MS_End;
}

int  MiniGameUrinal::ProcessPacketCmd(PacketBase* packet)
{
	int cmd;
	packet->ReadValue(cmd);
	switch(cmd)
	{
	case CMD_ManMove:
		{
			int from;
			int to;
			packet->ReadValue(from);
			packet->ReadValue(to);
	
			TryGo(from,to);
		}
		break;
	case CMD_ManPass:
		{
			Pass();
		}
		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;
}


//吃子
bool MiniGameUrinal::CheckFlip(Block* blockMap,int to)
{
	Block* toBlock = &blockMap[to];
	if (toBlock->man == SideNull)
	{
		return false;
	}
	int thisSide  = toBlock->man; 
	int otherSide = toBlock->man == SideRed?SideBlack:SideRed;

	int num = Count(blockMap,otherSide);
	if (num==1)//围捕阶段
	{
		return false;
	}

	
	bool flip = false;
	Block** pn = toBlock->neighbour;
	for(int d=0;d<8;++d,++pn)
	{
		Block* n = *pn;
		if (n==NULL)
		{
			continue;
		}
		Block* nn = n->neighbour[d];
		//顶
		if (nn  
			&& n->man==thisSide
			&& nn->man==otherSide 
			&& (nn->neighbour[d] == NULL || nn->neighbour[d]->man!=otherSide)//不是坠事蛋
			)
		{
			nn->man = thisSide;
			flip = true;
			num--;
			if (num==1)//围捕阶段
			{
				return true;
			}
		}

		Block* opn = toBlock->neighbour[opDir[d]];
		//顶
		if (opn  
			&& opn->man==thisSide
			&& n->man==otherSide 
			&& (nn == NULL || nn->man!=otherSide)//不是坠事蛋
			)
		{
			n->man = thisSide;
			flip = true;
			num--;
			if (num==1)//围捕阶段
			{
				return true;
			}
		}
		//夹
		if (nn  
			&& n->man==otherSide
			&& nn->man==thisSide 
			)
		{
			n->man = thisSide;
			flip = true;
			num--;
			if (num==1)//围捕阶段
			{
				return true;
			}
		}

		Block* opnn = NULL;
		if(opn) opnn = opn->neighbour[opDir[d]];
		//挑
		if (opn  
			&& opn->man==otherSide
			&& n->man==otherSide 
			&& (nn == NULL || nn->man!=otherSide)//不是坠事蛋
			&& (opnn == NULL || opnn->man!=otherSide)//不是坠事蛋
			)
		{
			n->man = thisSide;
			num--;
			if (num==1)//围捕阶段
			{
				return true;
			}
			opn->man = thisSide;
			num--;
			if (num==1)//围捕阶段
			{
				return true;
			}
			flip = true;
		}
	}

	return flip;
}


int  MiniGameUrinal::AlphaBeta( Block* blockMap,int depth,int alpha,int beta,ManSide side,vec2I&resOP,bool minmax /*=true*/,bool first/*=true*/ )
{
	if (depth == 0 
		//|| no sub
		) 
		return Envalue(blockMap,side);//局面的评分

	Block subMap[BlockNum];//4层嵌套, 内存占用不大 
	//拓扑邻居
	MakeNeighbour(blockMap,subMap);

	vec2I op;
	std::list<vec2I> opList;//所有可能的走法

	int old;
	int best;
	if(minmax == true)//play side A
	{
		//搜集所有可能的走法
		Search(blockMap,side,&opList);

		//对于alpha-beta剪枝算法,需要配合排序,优先搜索最好的走法,增加剪枝的效率。
		//opList.sort();

		//直接剪枝 只保留N个最好的走法

		best = INT_MIN; 
		old  = best;

		while(opList.empty()==false) //子树不空
		{
			op = opList.front();
			opList.pop_front();
			//根据初状态及走法构造子状态
			MakeSub(blockMap,subMap,op);

			best  = max(best, AlphaBeta(subMap,depth-1,alpha,beta,side,resOP,false,false)); //A取更高分给A
			alpha = max(alpha,best);

			if (first && best > old)
			{
				resOP = op;
			}
			old = best;


			if(beta < alpha)     //beta裁剪,B的下一步使A获得的分数更高 => 剪枝(B不会选这个节点)
				break;
		}
	}
	else//player other B
	{
		//搜集所有可能的走法
		Search(blockMap,side,&opList);

		//对于alpha-beta剪枝算法,需要配合排序,优先搜索最好的走法,增加剪枝的效率。
		//opList.sort();

		best = INT_MAX; 
		while(opList.empty()==false) //子树不空
		{
			op = opList.front();
			opList.pop_front();
			//根据初状态及走法构造子状态
			MakeSub(blockMap,subMap,op);

			best = min(best, AlphaBeta(subMap,depth-1,alpha,beta,side,resOP,true,false)); //B取更低分给A
			beta = min(beta,best);
			if( beta < alpha) //alpha裁剪
				break;
		}
	}
	return best;
}

bool MiniGameUrinal::UrinalThink(int side,int &resFrom, int &resTo )
{
	//无路可走 且没进罐子
	if (Count(m_blocks,side)==1)
	{
		Block* tiger = Tiger(m_blocks);
		bool way = false;
		for(int d=0;d<8;++d)
		{
			if (tiger->neighbour[d] && tiger->neighbour[d]->man==SideNull)
			{
				way = true;
				break;
			}
		}
		if(way==false)
			return false;
	}


	//minimax算法
	if (0)
	{
		vec2I resOP;
		AlphaBeta(m_blocks,ThinkDepth,INT_MIN,INT_MAX,(ManSide)side,resOP);
		resFrom = resOP.x;
		resTo   = resOP.y;
		return true;
	}
	
 
	//直接剪枝 只保留1个最好的走法
	Block subMap[BlockNum];
	//拓扑邻居
	MakeNeighbour(m_blocks,subMap);

	//搜集所有可能的走法
	std::list<vec2I> opList;
	Search(m_blocks,side,&opList);
	//OutputDebugText(opList.size());

	int score = 0;
	for(std::list<vec2I>::iterator it=opList.begin();it!=opList.end();++it)
	{
		//根据初状态及走法构造子状态
		MakeSub(m_blocks,subMap,*it);
		int s = Envalue(subMap,side);
		if (s>score)
		{
			score = s;
			resFrom = it->x;
			resTo   = it->y;
		}
	}
	return true;
}

void MiniGameUrinal::Search(Block* blockMap,int side, void* opList_ )
{
	vec2I op;
	std::list<vec2I>& opList = *((std::list<vec2I>*)opList_);
	opList.clear();
	Block* block = blockMap;
	for(int i=0;i<BlockNum;++i,++block)
	{
		if (block->man==side)
		{
			for(int d=0;d<8;++d)
			{
				Block* to = block;
				for(int step=0;step<5;++step)
				{
					to = to->neighbour[d];
					if(to==NULL || to->man!=SideNull)
						break;

					op.x = block->id;
					op.y = to->id;
					opList.push_back(op);
				}
			}
		}
	}
}

void MiniGameUrinal::MakeSub( Block* blockMap,Block* subMap,vec2I& op )
{
	拓扑邻居 
	//MakeNeighbour(blockMap,subMap);

	//copy
	for(int b=0;b<BlockNum;b++)
	{
		subMap[b].man = m_blocks[b].man;
	}

	Block* from = &subMap[op.x];
	Block* to   = &subMap[op.y];
	//if(to==NULL || to->man!=SideNull)
	//	return;
	to->man = from->man;
	from->man = SideNull;
	CheckFlip(subMap,op.y);
}

int  MiniGameUrinal::Envalue( Block* blockMap,int side )
{
	//使用多层minimax算法后,评分函数可以简化

	int num = Count(blockMap,side);
	if (num==9)//围捕阶段
	{
		num = 900;
		Block* tiger = Tiger(blockMap);

		对手走通罐子更好,对于不规则棋盘可以预生成路径
		//if(tiger->neighbour[RIGHT]!=NULL
		//	||(tiger->pos.y<2 && (tiger->neighbour[UP]!=NULL || tiger->neighbour[UPRIGHT]!=NULL) )
		//	||(tiger->pos.y>2 && (tiger->neighbour[DOWN]!=NULL || tiger->neighbour[DOWNRIGHT]!=NULL) )
		//	)
		//{
		//	num += 1000;
		//}

		对手活动空间越小越好 
		//Block* block = blockMap;
		//for(int i=0;i<BlockNum;++i,++block)
		//{
		//	if (block->man==side)
		//	{
		//		num += block->pos.x + 2-abs(tiger->pos.y-2);
		//	}
		//}

		Block* block = blockMap;
		for(int i=0;i<BlockNum;++i,++block)
		{
			block->flag = 0;
		}

		num += 10000;
		std::list<Block*> blockList;
		blockList.push_back(tiger);
		while(blockList.empty()==false)
		{
			Block* it = blockList.back();
			blockList.pop_back();
			Block** pn = it->neighbour;
			for(int d=0;d<8;++d,++pn)
			{
				Block* n = *pn;
				if (n && n->man==SideNull && n->flag==0)
				{
					blockList.push_back(n);
					n->flag = 1;
					num -= 100;//对手活动空间越小越好
				}
			}
		}

		//修正老虎进了菱形后,分数相同的话,我方不往里面进
		if (tiger->pos.x>4)
		{
			block = blockMap;
			for(int i=0;i<BlockNum;++i,++block)
			{
				if (block->man==side)
				{
					num += 5 - 2*abs(5-block->pos.x) + 2-abs(block->pos.y-2); //x*2, 否则x+y不变还是不进
				}
			}
		}
		

		//对手走通罐子更好
		if (blockMap[28].flag)
		{
			num += 100000;
		}
	}
	else if (num==1)//被围捕阶段
	{
		//自己越靠近罐子分数越低
		Block* tiger = Tiger(blockMap);
		num = 100 - tiger->pos.x*10 + abs(tiger->pos.y-2);
	}
	else
	{
		num*=100;//200~800
	}
	return num;
}

int  MiniGameUrinal::Count( Block* blockMap,int side )
{
	int num = 0;
	Block* block = blockMap;
	for(int i=0;i<BlockNum;++i,++block)
	{
		if (block->man==side)
		{
			num++;
		}
	}
	return num;
}

MiniGameUrinal::Block* MiniGameUrinal::Tiger( Block* blockMap )
{
	int num = 0;
	Block* tigerRed;
	Block* tigerBlack;
	Block* block = blockMap;
	for(int i=0;i<BlockNum;++i,++block)
	{
		if (block->man==SideRed)
		{
			num++;
			tigerRed = block;
		}
		if (block->man==SideBlack)
		{
			tigerBlack = block;
		}
	}
	if (num==1)
	{
		return tigerRed;
	}
	else if(num==9)
	{
		return tigerBlack;
	}
	return NULL;
}

void MiniGameUrinal::MakeNeighbour( Block* blockMap,Block* subMap )
{
	for(int b=0;b<BlockNum;b++)
	{
		subMap[b] = blockMap[b];
		for(int d=0;d<8;++d)
		{
			if (subMap[b].neighbour[d])
			{
				subMap[b].neighbour[d] = &subMap[subMap[b].neighbour[d]->id];
			}
			else
			{
				subMap[b].neighbour[d] = NULL;
			}
		}
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值