evaluation.cpp

来自「用c++ 开发的中国象棋」· C++ 代码 · 共 958 行 · 第 1/2 页

CPP
958
字号
// Evaluation.cpp: implementation of the CEvaluation class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ChineseChess.h"
#include "Evaluation.h"
#include "define.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//以下定义基本价值
#define BV_Soldier       100
#define BV_Assist	    250
#define BV_Bishop      250
#define BV_House		 700
#define BV_Gunner		 700
#define BV_Rook		    1500
#define BV_King	        10000

//定义棋子灵活性,也就是每多一个可走位置应加的分值
//兵15,士1,象1,车6,马12,炮6,将0
#define F_Soldier	 15
#define F_Assist     1
#define F_Bishop    1
#define F_Rook		 6
#define F_House	   12
#define F_Gunner	 6
#define F_King     0

//定义最大值
#define MAX_NUMBER 20000
#define NEG_MAX_NUMBER -20000

CEvaluation::~CEvaluation()
{

}
//红兵的附加值矩阵
const int RedSoldier_AddValue[10][9]=
{
	{0,0,0,0,0,0,0,0,0},
	{120,120,140,150,150,150,140,120,120},
	{120,120,140,150,150,150,140,120,120},
	{100,120,140,140,140,140,140,120,100},
	{100,100,100,100,100,100,100,100,100},
	{0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0},
};

//黑卒的附加值矩阵
const int BlackSoldier_AddValue[10][9]=
{
	{0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0},
	{100,100,100,100,100,100,100,100,100},
	{100,120,140,140,140,140,140,120,100},
	{120,120,140,150,150,150,140,120,120},
	{120,120,140,150,150,150,140,120,120},
	{0,0,0,0,0,0,0,0,0},
};



CEvaluation::CEvaluation()
{
	//初始化每种棋子的基本价值数组
	m_BaseValue[BlackKing]=BV_King;
	m_BaseValue[BlackRook]=BV_Rook;
	m_BaseValue[BlackHouse]=BV_House;
	m_BaseValue[BlackAssist]=BV_Assist;
	m_BaseValue[BlackBishop]=BV_Bishop;
	m_BaseValue[BlackGunner]=BV_Gunner;
	m_BaseValue[BlackSoldier]=BV_Soldier;

	m_BaseValue[RedKing]=BV_King;
	m_BaseValue[RedRook]=BV_Rook;
	m_BaseValue[RedHouse]=BV_House;
	m_BaseValue[RedAssist]=BV_Assist;
	m_BaseValue[RedBishop]=BV_Bishop;
	m_BaseValue[RedGunner]=BV_Gunner;
	m_BaseValue[RedSoldier]=BV_Soldier;

	//初始化灵活性分值数组
	m_FlexValue[BlackKing]=F_King;
	m_FlexValue[BlackRook]=F_Rook;
	m_FlexValue[BlackHouse]=F_House;
	m_FlexValue[BlackAssist]=F_Assist;
	m_FlexValue[BlackBishop]=F_Bishop;
	m_FlexValue[BlackGunner]=F_Gunner;
	m_FlexValue[BlackSoldier]=F_Soldier;

	m_FlexValue[RedKing]=F_King;
	m_FlexValue[RedRook]=F_Rook;
	m_FlexValue[RedHouse]=F_House;
	m_FlexValue[RedAssist]=F_Assist;
	m_FlexValue[RedBishop]=F_Bishop;
	m_FlexValue[RedGunner]=F_Gunner;
	m_FlexValue[RedSoldier]=F_Soldier;

	m_nAccessCount=0;
}



int CEvaluation::Eveluate(BYTE position[][9], BOOL bIsRedTurn,int nUserChessColor)
{
	int i,j,k;
	int nChessType,nTargetType;
	
	m_nAccessCount++;//每调用一次就增加一次

	//初始化
	memset(m_chessValue,0,360);
	memset(m_AttackPos,0,180);
	memset(m_GuardPos,0,90);
	memset(m_FlexibilityPos,0,90);

	//扫描棋盘,找出每一个棋子,及其威胁/保护的棋子,还有其灵活性
	for(i=0;i<10;i++)
		for(j=0;j<9;j++)
		{
			if(position[i][j]!=NoChessMan)
			{
				nChessType=position[i][j];   //取棋子类型
				GetRelatePiece(position,j,i);//找出该棋子所有相关位置
				for(k=0;k<nPosCount;k++)     //对每一目标位置
				{				
					nTargetType=position[RelatePos[k].y][RelatePos[k].x];//取目标棋子类型
					if(nTargetType==NoChessMan)//如果是空白,灵活性增加
						m_FlexibilityPos[i][j]++;
					else//有棋子
					{
						if(IsSameSide(nChessType,nTargetType))
						{
							//己方棋子,目标受保护
							m_GuardPos[RelatePos[k].y][RelatePos[k].x]++;
						}
						else
						{
							//敌方棋子,目标受威胁
							m_AttackPos[RelatePos[k].y][RelatePos[k].x]++;
							m_FlexibilityPos[i][j]++;//灵活性增加
							switch(nTargetType)
							{
								case RedKing://红帅
									if(!bIsRedTurn)//轮到黑棋走
										return MAX_NUMBER;//返回失败极值
									break;
								
								case BlackKing://黑将
									if(bIsRedTurn)//轮到红棋走
										return MAX_NUMBER;//返回失败极值
									break;
									
								default:
									//根据威胁的棋子加上威胁分值
									m_AttackPos[RelatePos[k].y][RelatePos[k].x]+=
										(30 +(m_BaseValue[nTargetType]- m_BaseValue[nChessType])/10)/10;
									break;
							}
						}
					}
				}
			}
		}

	//下面的循环统计扫描到的数据
	for(i=0;i<10;i++)
		for(j=0;j<9;j++)
		{
			if(position[i][j]!=NoChessMan)
			{
				nChessType=position[i][j];
				m_chessValue[i][j]++;
				//如果棋子存在其价值不为0,把每一棋子的灵活性价值加进棋子价值
				m_chessValue[i][j]+=m_FlexValue[nChessType]*m_FlexibilityPos[i][j];
				//加上兵的附加值
				m_chessValue[i][j]+=GetSoldierValue(j,i,position);
			}
		}

	//下面的循环继续统计扫描到的数据
	int nHalfvalue;
	for(i=0;i<10;i++)
		for(j=0;j<9;j++)
		{
			if(position[i][j]!=NoChessMan)
			{
				nChessType=position[i][j];			
				//棋子基本价值的1/16作为威胁/保护增量			
				nHalfvalue=m_BaseValue[nChessType]/16;     
				//每个棋子的基本价值加入其总价值
				m_chessValue[i][j]+=m_BaseValue[nChessType];
				if(IsRed(nChessType))//红棋
				{
					if(m_AttackPos[i][j])//当前红棋如果被威胁
					{
						if(bIsRedTurn)//轮到红棋走
						{						
							if(nChessType==RedKing)//如果是红将
								m_chessValue[i][j]-=20;//价值降低20
							else
							{
								//价值减去2倍nHalfvalue
								m_chessValue[i][j]-=nHalfvalue*2;
								if(m_GuardPos[i][j])//是否被己方棋子保护
									m_chessValue[i][j]+=nHalfvalue;//被保护再加上nHalfvalue
							}
						}
						else//当前红棋被威胁,轮到黑棋走
						{
							if(nChessType==RedKing)//是否是红帅
								return MAX_NUMBER;//返回失败极值	
							m_chessValue[i][j]-=nHalfvalue*10;//减去10倍的nHalfvalue,表示威胁程度高
							if(m_GuardPos[i][j])//如果被保护
								m_chessValue[i][j]+=nHalfvalue*9;//被保护再加上9倍的nHalfvalue
						}
						//被威胁的棋子加上威胁差,防止一个兵威胁
						//一个被保护的车,而估值函数没有反映此类问题
						m_chessValue[i][j]-=m_AttackPos[i][j];
					}
					else
					{
						//没受威胁
						if(m_GuardPos[i][j])
							m_chessValue[i][j]+=5;//受保护,加一点分
					}
				}
				else
				{
					//如果是黑棋
					if(m_AttackPos[i][j])
					{
						//受威胁
						if(!bIsRedTurn)
						{
							//轮到黑棋走
							if(nChessType==BlackKing)//如果是黑将
								m_chessValue[i][j]-=20;//棋子价值降低20
							else
							{ 
								//棋子价值降低2倍nHalfvalue
								m_chessValue[i][j]-=nHalfvalue*2;
								if(m_GuardPos[i][j])//如果受保护									
									m_chessValue[i][j] +=nHalfvalue;//棋子价值增加nHalfvalue
							}
						}
						else
						{
							//轮到红棋走
							if(nChessType==BlackKing)//是黑将
								return 18888;//返回失败极值							
							m_chessValue[i][j]-=nHalfvalue*10;//棋子价值减少10倍nHalfvalue
							if(m_GuardPos[i][j])//受保护
								m_chessValue[i][j]+=nHalfvalue*9;//被保护再加上9倍nHalfvalue
						}
						//被威胁的棋子再加上威胁差
						//防止一个兵威胁一个被保护的车,而估值函数没有反映此类的问题
						m_chessValue[i][j]-=m_AttackPos[i][j];
					}
					else
					{
						//不受威胁
						if(m_GuardPos[i][j])
							m_chessValue[i][j]+=5;//受保护,加一点分
					}
				}
			}
		}
		
	//以上统计了每个棋子的总价值
	//下面统计红黑两方总分
	int nRedValue=0;int nBlackValue=0;
	for(i=0;i<10;i++)
		for(j=0;j<9;j++)
		{
			nChessType=position[i][j];
			if(nChessType!=NoChessMan)
			{
				if(IsRed(nChessType))
					nRedValue+=m_chessValue[i][j];  //把红棋的值加总
				else
					nBlackValue+=m_chessValue[i][j];//把红棋的值加总
			}
		}

	if(nUserChessColor==REDCHESS)
	{
		if(bIsRedTurn)
			return nRedValue-nBlackValue;//如果轮到红棋走返回估值

		return nBlackValue-nRedValue;//如果轮到黑棋走返回负估值
	}

	if(bIsRedTurn)
		return nBlackValue-nRedValue;//如果轮到黑棋走返回负估值			
	
	return nRedValue-nBlackValue;//如果轮到红棋走返回估值
}

int CEvaluation::GetRelatePiece(BYTE position[][9], int j, int i)
{
	nPosCount=0;
	BYTE nChessID;
	BYTE flag;
	int x,y;
	
	nChessID=position[i][j];

	switch(nChessID)
	{
	case RedKing://红帅
	case BlackKing://黑将
		//循环检查九宫之内哪些位置可到达/保护
		//扫描两边就宫包含了照像的情况
		for(y=0;y<3;y++)
			for(x=3;x<6;x++)
				if(CanMoveTo(position,j,i,x,y))//能否到达
					AddPoint(x,y);//可达到/保护的位置加入数组

		//循环检查九宫之内哪些位置可到达/保护
		//扫描两边就宫包含了照像的情况
		for(y=7;y<10;y++)
			for(x=3;x<6;x++)
				if(CanMoveTo(position,j,i,x,y))//能否到达
					AddPoint(x,y);//可达到/保护的位置加入数组

		break;

	case RedAssist://红士
		//循环检查九宫之内哪些位置可到达/保护
		for(y=7;y<10;y++)
			for(x=3;x<6;x++)
				if(CanMoveTo(position,j,i,x,y))
					AddPoint(x,y);//可达到/保护的位置加入数组
		
		break;

	case BlackAssist://黑士
		//循环检查九宫之内哪些位置可到达/保护
		for(y=0;y<3;y++)
			for(x=3;x<6;x++)
				if(CanMoveTo(position,j,i,x,y))
					AddPoint(x,y);//可达到/保护的位置加入数组
		
		break;

	case RedBishop://红相
	case BlackBishop://黑象
		//右下
		x=j+2;
		y=i+2;
		if(x<9 && y<10 && CanMoveTo(position,j,i,x,y))
			AddPoint(x,y);

		//右上
		x=j+2;
		y=i-2;
		if(x<9 && y>=0 && CanMoveTo(position,j,i,x,y))
			AddPoint(x,y);

		//左下
		x=j-2;
		y=i+2;
		if(x>=0 && y<10 && CanMoveTo(position,j,i,x,y))
			AddPoint(x,y);

		//左上
		x=j-2;
		y=i-2;
		if(x>=0 && y>=0 && CanMoveTo(position,j,i,x,y))
			AddPoint(x,y);

		break;

		case RedHouse://红马
		case BlackHouse://黑马
			//检查右下方能否到达/保护
			x=j+2;
			y=i+1;
			if((x<9 && y<10)&&CanMoveTo(position,j,i,x,y))
				AddPoint(x,y);

			//检查右上方能否到达/保护
			x=j+2;
			y=i-1;
			if((x<9 && y>=0)&&CanMoveTo(position,j,i,x,y))
				AddPoint(x,y);

			//检查左下方能否到达/保护
			x=j-2;
			y=i+1;
			if((x>=0 && y<10)&&CanMoveTo(position,j,i,x,y))
				AddPoint(x,y);

			//检查左上方能否到达/保护
			x=j-2;
			y=i-1;
			if((x>=0 && y>=0)&&CanMoveTo(position,j,i,x,y))
				AddPoint(x,y);

			//检查右下方能否到达/保护
			x=j+1;
			y=i+2;
			if((x<9 && y<10)&&CanMoveTo(position,j,i,x,y))
				AddPoint(x,y);

			//检查右上方能否到达/保护
			x=j+1;
			y=i-2;
			if((x<9 && y>=0)&&CanMoveTo(position,j,i,x,y))
				AddPoint(x,y);

			//检查左下方能否到达/保护
			x=j-1;
			y=i+2;
			if((x>=0 && y<10)&&CanMoveTo(position,j,i,x,y))
				AddPoint(x,y);

			//检查左上方能否到达/保护
			x=j-1;
			y=i-2;
			if((x>=0 && y>=0)&&CanMoveTo(position,j,i,x,y))
				AddPoint(x,y);

			break;

		case RedRook://红车
		case BlackRook://黑车
			//检查向右能否到达/保护
			x=j+1;
			y=i;
			while(x<9)
			{
				if(NoChessMan==position[y][x])//空白
					AddPoint(x,y);
				else{
					//碰到第一个棋子
					AddPoint(x,y);
					break;//后面的位置不能走了
				}
				x++;
			}

			//检查向左能否到达/保护
			x=j-1;
			y=i;
			while(x>=0)
			{
				if(NoChessMan==position[y][x])//空白
					AddPoint(x,y);
				else{
					//碰到第一个棋子
					AddPoint(x,y);
					break;//后面的位置不能走了
				}
				x--;
			}

			//检查向下能否到达/保护
			x=j;
			y=i+1;
			while(y<10)
			{
				if(NoChessMan==position[y][x])//空白

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?