VC++源码分析 - 中国象棋源码分析

来源:互联网 发布:java分布式应用有哪些 编辑:程序博客网 时间:2024/06/10 04:03

下载自

http://www.newxing.com/Code/VC/game/1750.html


运行界面如下;


看下类图;


资源;


主对话框;



源码说明:

   本人机对弈程序采用了多种搜索算法.以下是本程序主要的类说明:
   1.CEveluation类:估值类,对给定的棋盘进行估值.


   2.CMoveGenerator类:走法产生器,对给定的棋盘局面搜索出所有可能的走法.


   3.CSearchEngine类:搜索引擎基类.
   4.CNegaMaxEngine类:负极大值法搜索引擎.
   5.CAlphaBetaEngine类:采用了Alpha-Beta剪枝技术的搜索引擎.
   6.CFAlphaBetaEngine类:fail-softalpha-beta搜索引擎.
   7.CHistoryHeuristic类:历史启发类.
   8.CAlphabeta_HHEngine类:带历史启发的Alpha-Beta搜索引擎.
   9.CAspirationSearch类:渴望搜索引擎.
   10.CIDAlphabetaEngine类:迭代深化搜索引擎.
   11.CMTD_fEngine类:MTD(f)搜索引擎.
   12.CTranspositionTable类:置换表.
   13.CAlphaBeta_TTEngine类:加置换表的Alpha-Beta搜索引擎.
   14.CPVS_Engine类:极小窗口搜索引擎.
   15.CNegaScout_TT_HH类:使用了置换表和历史启发的NegaScout搜索引擎.
本程序还具有悔棋,还原功能,还可以记录走法.


那么该源码可以参照写各类搜索引擎;


下面看下其部分代码;主对话框类;








可以看到最多的函数类别是各种菜单的消息映射函数;如下;

BEGIN_MESSAGE_MAP(CChessDlg, CDialog)//{{AFX_MSG_MAP(CChessDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_MOUSEMOVE()ON_COMMAND(IDM_SETCHESSBOARD, OnSetchessboard)ON_COMMAND(IDM_SET, OnSet)ON_COMMAND(IDM_ABOUT, OnAbout)ON_COMMAND(IDM_OPENFILE, OnOpenfile)ON_COMMAND(IDM_SAVEFILE, OnSavefile)ON_COMMAND(IDM_SCBOVER, OnScbover)ON_COMMAND(IDM_RPAWN, OnRpawn)ON_COMMAND(IDM_RCANON, OnRcanon)ON_COMMAND(IDM_RCAR, OnRcar)ON_COMMAND(IDM_RHORSE, OnRhorse)ON_COMMAND(IDM_RELEPHANT, OnRelephant)ON_COMMAND(IDM_RBISHOP, OnRbishop)ON_COMMAND(IDM_RKING, OnRking)ON_COMMAND(IDM_BPAWN, OnBpawn)ON_COMMAND(IDM_BCANON, OnBcanon)ON_COMMAND(IDM_BCAR, OnBcar)ON_COMMAND(IDM_BHORSE, OnBhorse)ON_COMMAND(IDM_BELEPHANT, OnBelephant)ON_COMMAND(IDM_BBISHOP, OnBbishop)ON_COMMAND(IDM_BKING, OnBking)ON_COMMAND(IDM_DELETE, OnDelete)ON_WM_RBUTTONDOWN()ON_WM_LBUTTONDBLCLK()ON_WM_CLOSE()ON_COMMAND(IDM_CLEARCB, OnClearcb)ON_COMMAND(IDM_NEWGAME, OnNewgame)ON_BN_CLICKED(IDC_BTNCOMPUTER, OnBtncomputer)ON_BN_CLICKED(IDC_BTNUNDO, OnBtnundo)ON_BN_CLICKED(IDC_BTNREDO, OnBtnredo)ON_LBN_DBLCLK(IDC_LISTCHESSRECORD, OnDblclkListchessrecord)ON_BN_CLICKED(IDC_BTN_STOP, OnBtnStop)ON_LBN_SELCHANGE(IDC_LISTCHESSRECORD, OnSelchangeListchessrecord)ON_COMMAND(IDM_PREVIEW, OnPreview)ON_COMMAND(IDM_PREVIEWOVER, OnPreviewover)ON_COMMAND(IDM_HELP, OnHelp)ON_COMMAND(IDM_INVERSECB, OnInversecb)//}}AFX_MSG_MAPEND_MESSAGE_MAP()


在对话框初始化函数中载入棋盘;

BITMAP BitMap;m_BoardBmp.LoadBitmap(IDB_CHESSBOARD);m_BoardBmp.GetBitmap(&BitMap); //取BitMap 对象m_nBoardWidth=BitMap.bmWidth;  //棋盘宽度m_nBoardHeight=BitMap.bmHeight;//棋盘高度


如上;棋盘是一个位图;

在对话框构造函数中创建三个重要的用于思考的对象:

m_pSE=new CNegaMaxEngine;//创建负极大值搜索引擎m_pMG=new CMoveGenerator;//创建走法产生器m_pEvel=new CEveluation; //创建估值核心

鼠标左键弹起时将用户走法压栈;也就是说用户走法用栈存储;

//---------将用户走法压栈---------m_cmBestMove.From.x=m_ptMoveChess.x;m_cmBestMove.From.y=m_ptMoveChess.y;m_cmBestMove.To.x=x;m_cmBestMove.To.y=y;m_cmBestMove.nChessID=m_MoveChess.nChessID;m_umUndoMove.cmChessMove=m_cmBestMove;m_umUndoMove.nChessID=m_byChessBoard[y][x];m_stackUndoMove.push(m_umUndoMove);//--------------------------------


......
typedef struct
{
short nChessID;  //表明是什么棋子
CHESSMANPOS From;//起始位置
CHESSMANPOS To;  //走到什么位置
int Score;       //走法的分数
}CHESSMOVE;

......

CHESSMOVE m_cmBestMove;

CHESSMOVE是一个结构体;

......

stack<UNDOMOVE> m_stackUndoMove;//记录走法的栈,便于悔棋

......

m_stackUndoMove是一个栈;


走法产生器;



根据不同的子判断落点是否符合中国象棋规则;例如象,往四个方向走田字:

void CMoveGenerator::Gen_ElephantMove(BYTE position[10][9],int i,int j,int nPly){int x,y;//插入右下方的有效走法x=j+2;y=i+2;if(x<9 && y<10 && IsValidMove(position,j,i,x,y,m_nUserChessColor))AddMove(j,i,x,y,nPly,position[i][j]);//插入右上方的有效走法x=j+2;y=i-2;if(x<9 && y>=0 && IsValidMove(position,j,i,x,y,m_nUserChessColor))AddMove(j,i,x,y,nPly,position[i][j]);//插入左下方的有效走法x=j-2;y=i+2;if(x>=0 && y<10 && IsValidMove(position,j,i,x,y,m_nUserChessColor))AddMove(j,i,x,y,nPly,position[i][j]);//插入左上方的有效走法x=j-2;y=i-2;if(x>=0 && y>=0 && IsValidMove(position,j,i,x,y,m_nUserChessColor))AddMove(j,i,x,y,nPly,position[i][j]);}

搜索引擎基类;其他搜索引擎继承此类;

//Download by http://www.NewXing.com// SearchEngine.h: interface for the CSearchEngine class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_SEARCHENGINE_H__7A7237B9_0908_45D8_B102_94E342B174A5__INCLUDED_)#define AFX_SEARCHENGINE_H__7A7237B9_0908_45D8_B102_94E342B174A5__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include "Eveluation.h"#include "MoveGenerator.h"#include "GradientProgressCtrl.h"//搜索引擎的基类class CSearchEngine  {public:CSearchEngine();virtual ~CSearchEngine();public:virtual SearchAGoodMove(BYTE position[10][9])=0;        //走下一步CHESSMOVE GetBestMove(){return m_cmBestMove;};//得到最佳走法UNDOMOVE GetUndoMove(){return m_umUndoMove;};//得到悔棋走法void SetSearchDepth(int nDepth){m_nSearchDepth=nDepth;};//设定最大搜索深度void SetEveluator(CEveluation* pEval){m_pEval=pEval;};  //设定估值引擎void SetMoveGenerator(CMoveGenerator* pMG){m_pMG =pMG;};//设定走法产生器void SetThinkProgress(CGradientProgressCtrl* pThinkProgress){m_pThinkProgress=pThinkProgress;};//设定显示思考进度的进度条void SetUserChessColor(int nUserChessColor){m_nUserChessColor=nUserChessColor;};//设定用户为黑方或红方void UndoChessMove(BYTE position[10][9],CHESSMOVE* move,BYTE nChessID);//悔棋void RedoChessMove(BYTE position[10][9],CHESSMOVE* move);              //还原protected:int IsGameOver(BYTE position[10][9],int nDepth);//判断是否已分胜负BYTE MakeMove(CHESSMOVE* move);    //根据某一走法产生走了之后的棋盘void UnMakeMove(CHESSMOVE* move,BYTE nChessID); //恢复为走过之前的棋盘public:int m_nUserChessColor;protected:CGradientProgressCtrl* m_pThinkProgress;    //用以显示思考进度的进度条指针BYTE CurPosition[10][9];//搜索时用于记录当前节点棋盘状态的数组CHESSMOVE m_cmBestMove;//记录最佳走法UNDOMOVE m_umUndoMove;CMoveGenerator* m_pMG;//走法产生器CEveluation* m_pEval;//估值核心int m_nSearchDepth;//最大搜索深度int m_nMaxDepth;//当前搜索的最大搜索深度};#endif // !defined(AFX_SEARCHENGINE_H__7A7237B9_0908_45D8_B102_94E342B174A5__INCLUDED_)

CoolButton类;用于绘制主界面左下角的四个按钮;可以参照写自己的cool 按钮类;

//Download by http://www.NewXing.com// CoolButton.cpp : implementation file//#include "stdafx.h"#include "CoolButton.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CCoolButtonCCoolButton::CCoolButton(){#ifdef XS_FLAT_BUTTONm_MouseOnButton=FALSE;#endifm_hIcon=NULL;m_cyIcon=0;m_cxIcon=0;}CCoolButton::~CCoolButton(){}BEGIN_MESSAGE_MAP(CCoolButton, CButton)//{{AFX_MSG_MAP(CCoolButton)ON_WM_MOUSEMOVE()ON_WM_KILLFOCUS()//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CCoolButton message handlersvoid CCoolButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) {// TODO: Add your code to draw the specified itemCDC * pDC=CDC::FromHandle(lpDIS->hDC);unsigned int  IsPressed =(lpDIS->itemState&ODS_SELECTED);unsigned int  IsFocused =(lpDIS->itemState&ODS_FOCUS);unsigned int  IsDisabled =(lpDIS->itemState&ODS_DISABLED);CRect itemRect = lpDIS->rcItem;#ifndef XS_FLAT_BUTTONif(IsFocused){CBrush br(RGB(0,0,0));pDC->FrameRect(&itemRect,&br);itemRect.DeflateRect(1,1);}#endif//Fill with bkcolorCBrush br(GetSysColor(COLOR_BTNFACE));pDC->FillRect(&itemRect,&br);//Is pressed?if(IsPressed){#ifdef XS_FLAT_BUTTON//浅边界笔CPen penBtnHiLight(PS_SOLID,0,GetSysColor(COLOR_BTNHILIGHT));//阴影笔CPen penBtnShadow(PS_SOLID,0,GetSysColor(COLOR_BTNSHADOW));//绘边界阴影pDC->SelectObject(penBtnShadow);pDC->MoveTo(itemRect.left,itemRect.bottom-1);pDC->LineTo(itemRect.left,itemRect.top);pDC->LineTo(itemRect.right,itemRect.top);//绘浅边界pDC->SelectObject(penBtnHiLight);pDC->MoveTo(itemRect.left,itemRect.bottom-1);pDC->LineTo(itemRect.right-1,itemRect.bottom-1);pDC->LineTo(itemRect.right-1,itemRect.top-1);#elseCBrush brBtnShadow(GetSysColor(COLOR_BTNSHADOW));pDC->FrameRect(&itemRect,&brBtnShadow);#endif}else//没按下{CPen penBtnHiLight(PS_SOLID,0,GetSysColor(COLOR_BTNHILIGHT));CPen pen3DLight(PS_SOLID,0,GetSysColor(COLOR_3DLIGHT));CPen penBtnShadow(PS_SOLID,0,GetSysColor(COLOR_BTNSHADOW));CPen pen3DDKShadow(PS_SOLID,0,GetSysColor(COLOR_3DDKSHADOW));#ifdef XS_FLAT_BUTTONif(m_MouseOnButton==TRUE){pDC->SelectObject(penBtnHiLight);pDC->MoveTo(itemRect.left,itemRect.bottom-1);pDC->LineTo(itemRect.left,itemRect.top);pDC->LineTo(itemRect.right,itemRect.top);//pDC->SelectObject(penBtnShadow);pDC->MoveTo(itemRect.left,itemRect.bottom-1);pDC->LineTo(itemRect.right-1,itemRect.bottom-1);pDC->LineTo(itemRect.right-1,itemRect.top-1);}#elsepDC->SelectObject(penBtnHiLight);pDC->MoveTo(itemRect.left,itemRect.bottom-1);pDC->LineTo(itemRect.left,itemRect.top);pDC->LineTo(itemRect.right,itemRect.top);pDC->SelectObject(pen3DLight);pDC->MoveTo(itemRect.left+1,itemRect.bottom-1);pDC->LineTo(itemRect.left+1,itemRect.top+1);pDC->LineTo(itemRect.right,itemRect.top+1);pDC->SelectObject(pen3DDKShadow);pDC->MoveTo(itemRect.left,itemRect.bottom-1);pDC->LineTo(itemRect.right-1,itemRect.bottom-1);pDC->LineTo(itemRect.right-1,itemRect.top-1);pDC->SelectObject(penBtnShadow);pDC->MoveTo(itemRect.left+1,itemRect.bottom-2);pDC->LineTo(itemRect.right-2,itemRect.bottom-2);pDC->LineTo(itemRect.right-2,itemRect.top);#endif}#ifndef XS_FLAT_BUTTON//if(IsFocused){CRect focusRect = itemRect;focusRect.DeflateRect(3,3);pDC->DrawFocusRect(&focusRect);}#endif//获取文本CString title;GetWindowText(title);//绘制图标if(m_hIcon!=NULL){CRect iconRect = lpDIS->rcItem;//根据标题是否存在来设置不同的图标位置if(title.IsEmpty()==TRUE){iconRect.left+=((iconRect.Width()-m_cxIcon)/2);}else{iconRect.left+=6;}iconRect.top+=((iconRect.Height()-m_cyIcon)/2);if(IsPressed)iconRect.OffsetRect(1,1);pDC->DrawIcon(iconRect.TopLeft(),m_hIcon);}//绘标题CRect captionRect = lpDIS->rcItem;captionRect.left+=m_cxIcon;if(title.IsEmpty()==FALSE){pDC->SetBkMode(TRANSPARENT);captionRect.OffsetRect(0,-1);if(IsPressed)captionRect.OffsetRect(1,1);if(IsDisabled){captionRect.OffsetRect(1,1);pDC->SetTextColor(GetSysColor(COLOR_BTNHILIGHT));pDC->DrawText(title,-1,captionRect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);captionRect.OffsetRect(-1,-1);pDC->SetTextColor(GetSysColor(COLOR_BTNSHADOW));pDC->DrawText(title,-1,captionRect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);}else{pDC->DrawText(title,-1,captionRect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);}}}#ifdef XS_FLAT_BUTTONvoid CCoolButton::OnMouseMove(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultCWnd* pWnd;CWnd* pParent;CButton::OnMouseMove(nFlags, point);pWnd=GetActiveWindow();pParent=GetOwner();if((m_MouseOnButton==FALSE)&&(GetCapture()!=this)&&((pWnd!=NULL)&&(pWnd->m_hWnd==pParent->m_hWnd))){SetCapture();SetFocus();m_MouseOnButton=TRUE;Invalidate();UpdateWindow();}else{CRect rc;GetClientRect(&rc);if(!rc.PtInRect(point)){m_MouseOnButton=FALSE;Invalidate();UpdateWindow();ReleaseCapture();}}}#endif#ifdef XS_FLAT_BUTTONvoid CCoolButton::OnKillFocus(CWnd* pNewWnd) {CButton::OnKillFocus(pNewWnd);// TODO: Add your message handler code hereif(m_MouseOnButton==TRUE){m_MouseOnButton=FALSE;Invalidate();UpdateWindow();}}#endifvoid CCoolButton::SetIcon(HICON hIcon, BYTE cx, BYTE cy){m_hIcon  = hIcon;m_cxIcon = cx;m_cyIcon = cy;}BOOL CCoolButton::SubclassDlgItem(UINT nID, CWnd *pParent){BOOL retValue=CButton::SubclassDlgItem(nID,pParent);LONG bs=::GetWindowLong(m_hWnd,GWL_STYLE);bs|=BS_OWNERDRAW;::SetWindowLong(m_hWnd,GWL_STYLE,bs);return retValue;}

余下的有空再分析吧;


搜索算法是利用计算机的高性能来有目的的穷举一个问题解空间的部分或所有的可能情况,从而求出问题的解的一种方法。
搜索算法实际上是根据初始条件和扩展规则构造一棵“解答树”并寻找符合目标状态的节点的过程。

Minimax算法又名极小化极大算法,是一种找出失败的最大可能性中的最小值的算法。Minimax算法常用于棋类等由两方较量的游戏和程序,这类程序由两个游戏者轮流,每次执行一个步骤。我们众所周知的五子棋、象棋等都属于这类程序,所以说Minimax算法是基于搜索的博弈算法的基础。该算法是一种零总和算法,即一方要在可选的选项中选择将其优势最大化的选择,而另一方则选择令对手优势最小化的方法。

0 0