?? chessdlg.cpp
字號:
// ChessDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Chess.h"
#include "ChessDlg.h"
#include "NegamaxEngine.h"
#include "HyperLink.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
//電腦思考線程函數(shù)
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 };
CHyperLink m_staticMail;
CButton m_btnOk;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
public:
virtual BOOL PreTranslateMessage(MSG* pMsg);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
CBitmap m_bitmapOk;
CToolTipCtrl m_ToolTip;
//{{AFX_MSG(CAboutDlg)
virtual BOOL OnInitDialog();
virtual void OnOK();
afx_msg void OnStaticQq();
//}}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, IDC_STATIC_MAIL, m_staticMail);
DDX_Control(pDX, IDOK, m_btnOk);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
ON_BN_CLICKED(IDC_STATIC_QQ, OnStaticQq)
//}}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;//創(chuàng)建負(fù)極大值搜索引擎
m_pMG=new CMoveGenerator;//創(chuàng)建走法產(chǎn)生器
m_pEvel=new CEveluation; //創(chuàng)建估值核心
}
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);
//彩色進(jìn)度條設(shè)置
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),"單擊條目可以預(yù)覽以前局面,雙擊條目可以快捷悔棋");
m_Chessman.Create(IDB_CHESSMAN,36,14,RGB(0,255,0));//創(chuàng)建含有棋子圖形的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); //設(shè)定搜索層數(shù)為3
m_pSE->SetMoveGenerator(m_pMG);//給搜索引擎設(shè)定走法產(chǎn)生器
m_pSE->SetEveluator(m_pEvel); //給搜索引擎設(shè)定估值核心
m_pSE->SetUserChessColor(m_nUserChessColor);
//設(shè)定用戶為黑方或紅方
m_pSE->SetThinkProgress(&m_progressThink);
//設(shè)定進(jìn)度條
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);
//將繪制的內(nèi)容刷新到屏幕
MemDC.SelectObject(&pOldBmp);//恢復(fù)內(nèi)存Dc的原位圖
MemDC.DeleteDC(); //釋放內(nèi)存
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("現(xiàn)在處于預(yù)覽狀態(tài),如要下棋,請彈出右鍵菜單點 預(yù)覽完畢");
return;
}
if(m_bIsGameOver)
{
m_staticTip.SetWindowText("老兄,這盤棋下完了");
return;
}
if(m_bIsThinking)//電腦正在想
return;
int x,y;
//將坐標(biāo)換算成棋盤上的格子
y=(point.y-14)/GRILLEHEIGHT;
x=(point.x-15)/GRILLEWIDTH;
//判斷鼠標(biāo)是否在棋盤內(nèi),并且點中了用戶棋子
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);//備份棋盤
//將當(dāng)前棋子的信息裝入,記錄移動棋子的結(jié)構(gòu)中
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;
//讓棋子中點坐標(biāo)位于鼠標(biāo)所在點
point.x-=18;
point.y-=18;
m_MoveChess.ptMovePoint=point;
//重繪屏幕
InvalidateRect(NULL,FALSE);
UpdateWindow();
SetCapture();//獨占鼠標(biāo)焦點
}
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_bIsGameOver)
{
m_staticTip.SetWindowText("老兄,這盤棋下完了");
return;
}
if(m_bIsThinking || m_Status!=Chessing)
return;
BOOL bTurnSide=FALSE;
int x,y;
CString str;
//將坐標(biāo)換算成棋盤上的格子
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//否則恢復(fù)移動前的棋盤狀態(tài)
{
memcpy(m_byShowChessBoard,m_byBackupChessBoard,90);
memcpy(m_byChessBoard,m_byBackupChessBoard,90);
}
m_MoveChess.nChessID=NOCHESS;//將移動的棋子清空
//重繪屏幕
InvalidateRect(NULL,FALSE);
UpdateWindow();
ReleaseCapture();//釋放鼠標(biāo)焦點
if(m_iChessSort==CS_PPCHESS)
{
m_iWhoChess=m_iWhoChess%2+1;
return;
}
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;
//讓棋子中心位于鼠標(biāo)所在處
point.x-=18;
point.y-=18;
m_MoveChess.ptMovePoint=point;//保存移動棋子的坐標(biāo)
}
else
{
//讓棋子中心位于鼠標(biāo)所在處
point.x-=18;
point.y-=18;
m_MoveChess.ptMovePoint=point;//保存移動棋子的坐標(biāo)
//棋子拖出棋盤時將該棋子刪掉
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();//立即執(zhí)行刷新
}
CDialog::OnMouseMove(nFlags, point);
}
void CChessDlg::OnSetchessboard()
{
// TODO: Add your command handler code here
m_strOutputInfo=" 點擊鼠標(biāo)右鍵,可以增加棋子和刪除棋子";
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;//創(chuàng)建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;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -