⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chessdlg.cpp

📁 对弈程序采用了多种搜索算法.以下是本程序主要的类说明: 1.CEveluation类:估值类,对给定的棋盘进行估值. 2.CMoveGenerator类:走法产生器,对给定的棋盘局面搜索出
💻 CPP
📖 第 1 页 / 共 4 页
字号:
// ChessDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Chess.h"
#include "ChessDlg.h"
#include "NegamaxEngine.h"

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

#define GRILLEWIDTH  39//棋盘上每个格子的宽度
#define GRILLEHEIGHT 39//棋盘上每个格子的高度

const BYTE InitChessBoard[10][9]=
{
	{B_CAR,B_HORSE,B_ELEPHANT,B_BISHOP,B_KING,B_BISHOP,B_ELEPHANT,B_HORSE,B_CAR},
	{NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS},
	{NOCHESS,B_CANON,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,B_CANON,NOCHESS},
	{B_PAWN,NOCHESS,B_PAWN,NOCHESS,B_PAWN,NOCHESS,B_PAWN,NOCHESS,B_PAWN},
	{NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS},
	               //楚河                       汉界//
	{NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS},
	{R_PAWN,NOCHESS,R_PAWN,NOCHESS,R_PAWN,NOCHESS,R_PAWN,NOCHESS,R_PAWN},
	{NOCHESS,R_CANON,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,R_CANON,NOCHESS},
	{NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS,NOCHESS},
	{R_CAR,R_HORSE,R_ELEPHANT,R_BISHOP,R_KING,R_BISHOP,R_ELEPHANT,R_HORSE,R_CAR}
};

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

//电脑思考线程函数
DWORD WINAPI ThinkProc(LPVOID pParam)
{
	CChessDlg* pDlg=(CChessDlg*)pParam;

	pDlg->Think();

	return 0;
}

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	CButton	m_btnOk;
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	CBitmap m_bitmapOk;

	//{{AFX_MSG(CAboutDlg)
	virtual BOOL OnInitDialog();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
	m_bitmapOk.LoadBitmap(IDB_OK);
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	DDX_Control(pDX, IDOK, m_btnOk);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChessDlg dialog

CChessDlg::CChessDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CChessDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CChessDlg)
	m_strOutputInfo = _T(" 欢迎使用中国象棋      作者:陶善文");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_hUndoIcon=AfxGetApp()->LoadIcon(IDI_UNDO);
	m_hRedoIcon=AfxGetApp()->LoadIcon(IDI_REDO);
	m_hComputerIcon=AfxGetApp()->LoadIcon(IDI_COMPUTER);
	m_hStopIcon=AfxGetApp()->LoadIcon(IDI_STOP);

	m_iWhoChess=REDCHESS;
	m_Status=Chessing;
	m_bIsGameOver=false;
	m_nUserChessColor=REDCHESS;
	m_pMG=new CMoveGenerator;	
	m_bIsThinking=false;
	m_nWillChessColor=REDCHESS;
	m_bIsBegin=false;
	m_iBout=0;
	m_strWelcome=" 欢迎使用中国象棋      作者:陶善文";

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

void CChessDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CChessDlg)
	DDX_Control(pDX, IDC_BTN_STOP, m_btnStop);
	DDX_Control(pDX, IDC_BTNUNDO, m_btnUndo);
	DDX_Control(pDX, IDC_BTNREDO, m_btnRedo);
	DDX_Control(pDX, IDC_BTNCOMPUTER, m_btnComputer);
	DDX_Control(pDX, IDC_LISTCHESSRECORD, m_lstChessRecord);
	DDX_Control(pDX, IDC_PROGRESSTHINK, m_progressThink);
	DDX_Control(pDX, IDC_OUTPUTINFO, m_staticTip);
	DDX_Text(pDX, IDC_OUTPUTINFO, m_strOutputInfo);
	//}}AFX_DATA_MAP
}

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_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChessDlg message handlers

BOOL CChessDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	m_btnComputer.SetIcon(m_hComputerIcon,32,32);
	m_btnStop.SetIcon(m_hStopIcon,32,32);
	m_btnUndo.SetIcon(m_hUndoIcon,32,32);
	m_btnRedo.SetIcon(m_hRedoIcon,32,32);

	//彩色进度条设置
	m_progressThink.SetStartColor(RGB(0xFF,0xFF,0x00));//黄色
	m_progressThink.SetEndColor(RGB(0x00,0x93,0x00));  //绿色
	m_progressThink.SetBkColor(RGB(0xE6,0xE6,0xFA));   //淡紫色
	m_progressThink.SetTextColor(RGB(0,0,255));
	m_progressThink.ShowPercent(1);

	m_tooltip.Create(this);
	m_tooltip.Activate(1);
	m_tooltip.AddTool(GetDlgItem(IDC_LISTCHESSRECORD),"单击条目可以预览以前局面,双击条目可以快捷悔棋");

	m_Chessman.Create(IDB_CHESSMAN,36,14,RGB(0,255,0));//创建含有棋子图形的ImgList,用于绘制棋子

	//下面这段代码取棋盘图形的宽,高
	BITMAP BitMap;
	m_BoardBmp.LoadBitmap(IDB_CHESSBOARD);
	m_BoardBmp.GetBitmap(&BitMap); //取BitMap 对象
	m_nBoardWidth=BitMap.bmWidth;  //棋盘宽度
	m_nBoardHeight=BitMap.bmHeight;//棋盘高度

	m_BoardBmp.DeleteObject();

	memcpy(m_byChessBoard,InitChessBoard,90);//初始化棋盘
	memcpy(m_byShowChessBoard,InitChessBoard,90);
	memcpy(m_byBackupChessBoard,InitChessBoard,90);

	m_pSE->SetSearchDepth(3);      //设定搜索层数为3
	m_pSE->SetMoveGenerator(m_pMG);//给搜索引擎设定走法产生器
	m_pSE->SetEveluator(m_pEvel);  //给搜索引擎设定估值核心
	m_pSE->SetUserChessColor(m_nUserChessColor);
								   //设定用户为黑方或红方
	m_pSE->SetThinkProgress(&m_progressThink);
								   //设定进度条

	m_MoveChess.nChessID=NOCHESS;//将移动的棋子清空

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CChessDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CChessDlg::OnPaint() 
{
	CPaintDC dc(this);
	CDC MemDC;
	int i,j;
	POINT pt;
	CBitmap* pOldBmp;

	MemDC.CreateCompatibleDC(&dc);
	m_BoardBmp.LoadBitmap(IDB_CHESSBOARD);
	pOldBmp=MemDC.SelectObject(&m_BoardBmp);
	
	//绘制棋盘上的棋子
	for(i=0;i<10;i++)
		for(j=0;j<9;j++)
		{			
			if(m_byShowChessBoard[i][j]==NOCHESS)
				continue;

			pt.x=j*GRILLEHEIGHT+14;
			pt.y=i*GRILLEWIDTH+15;
			m_Chessman.Draw(&MemDC,m_byShowChessBoard[i][j]-1,pt,ILD_TRANSPARENT);
		}

	//绘制用户正在拖动的棋子
	if(m_MoveChess.nChessID!=NOCHESS)
		m_Chessman.Draw(&MemDC,m_MoveChess.nChessID-1,m_MoveChess.ptMovePoint,ILD_TRANSPARENT);
	dc.BitBlt(0,0,m_nBoardWidth,m_nBoardHeight,&MemDC,0,0,SRCCOPY);
								 //将绘制的内容刷新到屏幕
	MemDC.SelectObject(&pOldBmp);//恢复内存Dc的原位图	
	MemDC.DeleteDC();            //释放内存	 
	m_BoardBmp.DeleteObject();   //删除棋盘位图对象
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CChessDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CChessDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if(m_iChessSort==CS_CCCHESS)
	{
		m_staticTip.SetWindowText(m_strWelcome);
		return;
	}

	if(m_Status==Previewing)
	{
		m_staticTip.SetWindowText("现在处于预览状态,如要下棋,请弹出右键菜单点 预览完毕");

		return;
	}

	if(m_bIsGameOver)
	{
		m_staticTip.SetWindowText("老兄,这盘棋下完了");

		return;
	}

	if(m_bIsThinking)//电脑正在想
		return;

	int x,y;

	//将坐标换算成棋盘上的格子
	y=(point.y-14)/GRILLEHEIGHT;
	x=(point.x-15)/GRILLEWIDTH;
		
	//判断鼠标是否在棋盘内,并且点中了用户棋子
	if(y>=0 && y<10 && x>=0 && x<9 && (m_nUserChessColor==REDCHESS?IsRed(m_byChessBoard[y][x]):IsBlack(m_byChessBoard[y][x])))
	{
		memcpy(m_byBackupChessBoard,m_byChessBoard,90);//备份棋盘
		
		//将当前棋子的信息装入,记录移动棋子的结构中
		m_ptMoveChess.x=x;
		m_ptMoveChess.y=y;
		m_MoveChess.nChessID=m_byChessBoard[y][x];
		
		//将该棋子原位置棋子去掉
		m_byChessBoard[y][x]=NOCHESS;
		m_byShowChessBoard[y][x]=NOCHESS;
		
		//让棋子中点坐标位于鼠标所在点
		point.x-=18;
		point.y-=18;
		m_MoveChess.ptMovePoint=point;
		//重绘屏幕
		InvalidateRect(NULL,FALSE);
		UpdateWindow();
		SetCapture();//独占鼠标焦点
	}
	else
		if(m_Status==Chessing)
			if(y>=0 && y<10 && x>=0 && x<9 && (m_nUserChessColor!=REDCHESS?IsRed(m_byChessBoard[y][x]):IsBlack(m_byChessBoard[y][x])))
				m_staticTip.SetWindowText("不好意思,这是我的棋子,请你不要乱动");
			else
				m_staticTip.SetWindowText("老兄,那又没有棋子,你瞎点什么啊");

	CDialog::OnLButtonDown(nFlags, point);
}

void CChessDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if(m_Status!=Chessing)
		return;

	if(m_bIsGameOver)
	{
		m_staticTip.SetWindowText("老兄,这盘棋下完了");
		return;
	}

	if(m_bIsThinking || m_Status!=Chessing)
		return;

	BOOL bTurnSide=FALSE;
	int x,y;
	CString str;

    //将坐标换算成棋盘上的格子 
	y=(point.y-14)/GRILLEHEIGHT;
	x=(point.x-15)/GRILLEWIDTH;
	
	//判断是否有移动棋子,并且该棋子的移动是一个合法走法
//	if(m_MoveChess.nChessID && CMoveGenerator::IsValidMove(m_byBackupChessBoard,m_ptMoveChess.x,m_ptMoveChess.y,x,y,m_nUserChessColor))
	if(m_MoveChess.nChessID && m_pMG->IsValidMove(m_byBackupChessBoard,m_ptMoveChess.x,m_ptMoveChess.y,x,y,m_nUserChessColor))
	{
		//---------将用户走法压栈---------
		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);
		//--------------------------------

		m_btnUndo.EnableWindow(1);//激活悔棋按钮
		
		if(m_nUserChessColor==REDCHESS)
			m_iBout++;
		this->AddChessRecord(m_ptMoveChess.x+1,m_ptMoveChess.y+1,x+1,y+1,m_nUserChessColor,m_MoveChess.nChessID);
		m_byChessBoard[y][x]=m_MoveChess.nChessID;
		m_byShowChessBoard[y][x]=m_MoveChess.nChessID;
		bTurnSide=TRUE;
	}
	else//否则恢复移动前的棋盘状态
	{
		memcpy(m_byShowChessBoard,m_byBackupChessBoard,90);
		memcpy(m_byChessBoard,m_byBackupChessBoard,90);
	}
    
	m_MoveChess.nChessID=NOCHESS;//将移动的棋子清空

	//重绘屏幕  
	InvalidateRect(NULL,FALSE);
	UpdateWindow();	
	ReleaseCapture();//释放鼠标焦点

	if(bTurnSide==TRUE)
	{
		m_btnStop.EnableWindow(1);
		m_hHandle=::CreateThread(0,0,ThinkProc,this,0,&m_dwThreadID);
	}
	else
		m_staticTip.SetWindowText(m_strWelcome);

	CDialog::OnLButtonUp(nFlags,point);
}

void CChessDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if(m_bIsThinking)
		return;

	if(m_MoveChess.nChessID)
	{
		if(m_Status==Chessing)
		{
			//防止将棋子拖出棋盘
			if(point.x<15)//左边
				point.x=15;
			if(point.y<15)//上边
				point.y=15;
			if(point.x>m_nBoardWidth-15)//右边				
				point.x=m_nBoardWidth-15;
			if(point.y>m_nBoardHeight-15)//下边				
				point.y=m_nBoardHeight-15;
			
			//让棋子中心位于鼠标所在处
			point.x-=18;
			point.y-=18;
			
			m_MoveChess.ptMovePoint=point;//保存移动棋子的坐标	
		}
		else
		{
			//让棋子中心位于鼠标所在处
			point.x-=18;
			point.y-=18;
			
			m_MoveChess.ptMovePoint=point;//保存移动棋子的坐标	

			//棋子拖出棋盘时将该棋子删掉
			if(point.x<15 || point.y<15 || point.x>m_nBoardWidth-15 || point.y>m_nBoardHeight-15)
				m_byChessBoard[m_ptMoveChess.y][m_ptMoveChess.x]=NOCHESS;
		}

		InvalidateRect(NULL,FALSE);//刷新窗口
		UpdateWindow();//立即执行刷新
	}

	CDialog::OnMouseMove(nFlags, point);
}

void CChessDlg::OnSetchessboard() 
{
	// TODO: Add your command handler code here
	m_strOutputInfo=" 点击鼠标右键,可以增加棋子和删除棋子";
	UpdateData(false);
	m_Status=SetChessBoarding;
}

void CChessDlg::OnSet() 
{
	// TODO: Add your command handler code here
	if(m_bIsThinking || m_SetDlg.DoModal()==IDCANCEL)
		return;

	if(m_pSE)
		delete m_pSE;//释放旧的搜索引擎
	
	if(m_nUserChessColor!=m_SetDlg.GetUserChessColor())
		this->InvertChessBoard(m_byChessBoard);
	m_nUserChessColor=m_SetDlg.GetUserChessColor();
	m_iChessSort=m_SetDlg.GetChessSort();
	m_iDepthSort=m_SetDlg.GetDepthSort();

	if(m_iChessSort==CS_PCCHESS || m_iChessSort==CS_PPCHESS)
		m_btnComputer.EnableWindow(0);
	else
		m_btnComputer.EnableWindow(1);

	switch(m_SetDlg.GetSelectedEngine())
	{
	case 0:
		m_pSE=new CNegaMaxEngine;
		break;
		
	case 1:
		m_pSE=new CAlphaBetaEngine;//创建alpha-beta搜索引擎
		break;
		
	case 2:
		m_pSE=new CFAlphaBetaEngine;
		break;
		
	case 3:
		m_pSE=new CAspirationSearch;
		break;
		
	case 4:
		m_pSE=new CPVS_Engine;
		break;
		
	case 5:

⌨️ 快捷键说明

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