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

📄 chessdlg.cpp

📁 人工智能实现博弈,利用剪枝法搜索书,不过机器反应慢,但是人一般失误一次就输了!
💻 CPP
字号:
// ChessDlg.cpp : 实现文件
//

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

#ifdef _DEBUG
#define new DEBUG_NEW
#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}
};

////////////////////////////////////////////
DWORD WINAPI ThinkProc(LPVOID pParam)
{
	CChessDlg* pDlg=(CChessDlg*)pParam;
	pDlg->ThinkChess();
	return 0;
}

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();
// 对话框数据
	enum { IDD = IDD_ABOUTBOX };
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()

// CChessDlg 对话框

CChessDlg::CChessDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CChessDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	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_pSE=new CNegaMaxEngine;//创建负极大值搜索引擎
	m_pMG=new CMoveGenerator;//创建走法产生器
	m_pEvel=new CEveluation; //创建估值核心
}

void CChessDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_OUTPUTINFO, m_staticTip);
}

BEGIN_MESSAGE_MAP(CChessDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()	
	//}}AFX_MSG_MAP
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_COMMAND(ID_32773, On32773)
	ON_COMMAND(ID_32772, On32772)
	ON_COMMAND(ID_32771, On32771)
END_MESSAGE_MAP()
// CChessDlg 消息处理程序

BOOL CChessDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	// 将\“关于...\”菜单项添加到系统菜单中。
	// IDM_ABOUTBOX 必须在系统命令范围内。
	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);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	//创建含有棋子图形的ImgList,用于绘制棋子
	m_Chessman.Create(IDB_CHESSMAN,36,14,RGB(0,255,0));

	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_MoveChess.nChessID=NOCHESS;//将移动的棋子清空	
	return TRUE;  // 除非设置了控件的焦点,否则返回 TRUE
}

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

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。
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();   //删除棋盘位图对象
}

//当用户拖动最小化窗口时系统调用此函数取得光标显示。
HCURSOR CChessDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CChessDlg::ThinkChess()
{
	int timecount;
	CString sNodeCount;	
	timecount=GetTickCount();//取初始时间
	m_staticTip.SetWindowText("电脑正在搜索最佳走步,请等待...");	
	if(m_nUserChessColor==BLACKCHESS)
		m_iBout++;
	m_bIsThinking=true;
	m_pSE->SearchAGoodMove(m_byChessBoard);
	memcpy(m_byShowChessBoard,m_byChessBoard,90);
	memcpy(m_byBackupChessBoard,m_byChessBoard,90);
	m_cmBestMove=m_pSE->GetBestMove();//得到最佳走法	
	m_bIsThinking=false;	
	//重绘屏幕  
	InvalidateRect(NULL,FALSE);
	UpdateWindow();

	sNodeCount.Format("共搜索%d个节点,花费时间%.3fs",m_pEvel->GetAccessCount(),(GetTickCount()-timecount)/1000.0);
	m_staticTip.SetWindowText(sNodeCount);
	::FlashWindow(this->GetSafeHwnd(),TRUE);	
	m_pEvel->ClearAccessCount();	
	switch(IsGameOver(m_byChessBoard))
	{
	case -1:
		m_staticTip.SetWindowText("恭喜你,本局你获胜");
		break;

	case 1:
		m_staticTip.SetWindowText("很不幸,本局你失败了,继续努力");
		break;

	default:
		return;
	}
	
	m_bIsGameOver=true;
}


void CChessDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
		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: 在此添加消息处理程序代码和/或调用默认值
	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 && 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;
			
		if(m_nUserChessColor==REDCHESS)
			m_iBout++;
		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_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: 在此添加消息处理程序代码和/或调用默认值
   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);
}

// 判断游戏是否结束
int CChessDlg::IsGameOver(BYTE position[][9])
{
		int i,j;
	BOOL RedLive=FALSE,BlackLive=FALSE;

	//检查红方九宫是否有帅
	for(i=7;i<10;i++)
		for(j=3;j<6;j++)
		{
			if(position[i][j]==B_KING)
				BlackLive=TRUE;
			if(position[i][j]==R_KING)
				RedLive=TRUE;
		}

	//检查黑方九宫是否有将
	for(i=0;i<3;i++)
		for(j=3;j<6;j++)
		{
			if(position[i][j]==B_KING)
				BlackLive=TRUE;
			if(position[i][j]==R_KING)
				RedLive=TRUE;
		}

	if(m_nUserChessColor==REDCHESS)
	{
		if(!RedLive)
			return 1;		
		if(!BlackLive)
			return -1;
	}
	else
	{
		if(!RedLive)
			return -1;		
		if(!BlackLive)
			return 1;
	}
	return 0;
}


void CChessDlg::On32773()
{
	// TODO: 在此添加命令处理程序代码
	CAboutDlg dlgAbout;
	dlgAbout.DoModal();
}

void CChessDlg::On32772()
{
	// TODO: 在此添加命令处理程序代码
	if(MessageBox("你确定要退出吗?","提示",MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2)==IDNO)
		return;
	CDialog::OnCancel();
}

void CChessDlg::On32771()
{
	// TODO: 在此添加命令处理程序代码
	if(MessageBox("你确定要重新开始?","提醒",MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2)==IDNO)
		return;
	memcpy(m_byChessBoard,InitChessBoard,90);    //初始化棋盘
	memcpy(m_byShowChessBoard,InitChessBoard,90);
	memcpy(m_byBackupChessBoard,InitChessBoard,90);
	m_MoveChess.nChessID=NOCHESS;                //清除移动棋子
	m_bIsGameOver=false;	
	//刷新屏幕
	InvalidateRect(NULL,FALSE);
	UpdateWindow();
	m_bIsBegin=false;
	m_staticTip.SetWindowText(m_strWelcome);	
}

⌨️ 快捷键说明

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