📄 chessdlg.cpp
字号:
// 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 + -