简述
在学习了C++ MFC编程后,就萌生了编写一个五子棋程序的想法。诚然,用C#来编写的话可能界面会好很多,但是我的主要目标不在界面而是算法,所以利用了VS的MFC来编写程序。
程序实现
step1:在VS中创建一个MFC对话框程序(这一步骤可以参考具体教程,本文主要在于给出一个简单的实现)
step2:新建一个名为CMainGobang的类,在类中编写主要代码
(完整代码可访问我的github: https://github.com/Vaczzy/SimpleGobang)
- 在该类的头文件中添加需要用到的函数声明和结构体
struct Pieces//棋子判断单元
{
bool bIsPieces;//是否已有棋
bool bIsBlack;//黑棋或白棋
int x,y;//棋子所在格
};
struct MyRectangle
{
int x,y;//选中框核心坐标
};
public:
CMainGobang(void);
~CMainGobang(void);
private:
/////basic information
int iSize;//棋盘大小参数
int xmax,xmin,ymax,ymin;//棋盘大小参数
int idx;//棋盘每小格长度
/////pieces information
int iPieces;//棋子计数//当前棋子计数为iPieces-1
int iPiecesNum;//棋子总数
Pieces *pPieces;//棋子
/////rectangle information
int iRectangleNum;//选中框个数
MyRectangle *pmyRectangle;//选中框
/////for draw rectangle&draw pieces
bool NoRectangle(int x,int y);//判断该位置上是否有选中框
bool NoPieces(int x,int y);//判断该位置上是否有棋子
/////for judge win
bool IsBlack(int x,int y);//判断该位置上棋子颜色
bool IsConnect(int iDir,int x,int y);//查找相连的棋子
int ConnectNum();//返回相连棋子个数
/////for machine fight
//void MaConnectNum(int iConnectNum,int iDir);//返回弱相连棋子个数/iDir方向参数
int ConnectDir();//返回相连棋子方向
public:
void DrawMainTable(CDC *pDC,CRect rect,int iTableSize);//绘制棋盘函数
void SetPieces();//设参函数//将初始化代码与绘制棋盘代码分开
void DrawRectangle(CDC *pDC,CPoint pt);//绘制选中框/返回是否绘制
void DrawPieces(CDC *pDC,CRect rect,CPoint pt);//绘制棋子函数
bool ClearPieces(CDC *pDC,bool &bBlack);//清除棋子函数/用于悔棋
void KeepPieces(CDC *pDC,CRect rect,int iTableSize);//循环绘制棋子 //用以解决刷新问题
void MachineDraw(CDC *pDC);//机器下棋函数
bool Success();//判断胜利函数
void ReplayMark(CDC *pDC);//复盘标记函数
- 在该类的cpp文件中添加函数实现
(这里只列出了绘制棋盘的函数)
CMainGobang::CMainGobang(void)
{
}
CMainGobang::~CMainGobang(void)
{
if(pPieces!=NULL)
{
delete []pPieces;
pPieces=NULL;
}
if(pmyRectangle!=NULL)
{
delete []pmyRectangle;
pmyRectangle=NULL;
}
}
//绘制棋盘函数
//后期可添加棋盘大小参数
//控件坐标
void CMainGobang::DrawMainTable(CDC *pDC,CRect rect,int iTableSize)
{
iSize=iTableSize;
//先覆盖背景
CRect Back;
Back.top=rect.top+1;
Back.bottom=rect.bottom-1;
Back.left=rect.left+1;
Back.right=rect.right-1;
pDC->FillSolidRect(&Back,RGB(240,240,240));//填充
//计算每格长度
idx=(((rect.right-rect.left)/(iTableSize+1))>((rect.bottom-rect.top)/(iTableSize+1)))?
(rect.bottom-rect.top)/(iTableSize+1):
(rect.right-rect.left)/(iTableSize+1);
CBrush brush(RGB(0,0,0));
CBrush *OldBrush=pDC->SelectObject(&brush);
int ixp,iyp;//棋盘星坐标
//绘制天元
ixp=(rect.right-rect.left)/2;
iyp=(rect.bottom-rect.top)/2;
pDC->Ellipse(ixp-3,iyp-3,ixp+3,iyp+3);
//绘制星
ixp-=4*idx;
iyp-=4*idx;//左上角
pDC->Ellipse(ixp-3,iyp-3,ixp+3,iyp+3);
iyp+=8*idx;//左下角
pDC->Ellipse(ixp-3,iyp-3,ixp+3,iyp+3);
ixp+=8*idx;//右下角
pDC->Ellipse(ixp-3,iyp-3,ixp+3,iyp+3);
iyp-=8*idx;//右上角
pDC->Ellipse(ixp-3,iyp-3,ixp+3,iyp+3);
pDC->SelectObject(OldBrush);//恢复设备环境中原来的画笔
brush.DeleteObject();//释放绘图资源
//计算棋盘大小并放置于窗口中间
ymin=(rect.bottom-rect.top)/2-(iTableSize-1)/2*idx;
ymax=ymin+(iTableSize-1)*idx;
xmin=(rect.right-rect.left)/2-(iTableSize-1)/2*idx;
xmax=xmin+(iTableSize-1)*idx;
for(int x=xmin;x<=xmax;x+=idx)
{
pDC->MoveTo(x,ymin);
pDC->LineTo(x,ymax);
}
for(int y=ymin;y<=ymax;y+=idx)
{
pDC->MoveTo(xmin,y);
pDC->LineTo(xmax,y);
}
}
step3:在xxxx(xxxx为你创建的工程名)Dlg.cpp中编写与界面有关的代码
这一步主要是编写一些与界面有关的代码
比如在鼠标移动过程中在其对应的棋格的位置绘制一个矩形框(图见后文)
//鼠标移动函数
void CMyGobang_DHKDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CPoint pt;
CRect rect;
GetDlgItem(IDC_MainTable)->GetWindowRect(&rect);//获取控件屏幕坐标
GetCursorPos(&pt);//获取鼠标点击坐标(屏幕坐标坐标)
pt.x-=rect.left;//转化为控件中坐标
pt.y-=rect.top;
CDC *pDC=picMain.GetDC();//获取该控件的画布
if(bIsReady)
{
gobang.DrawRectangle(pDC,pt);
}
CDialogEx::OnMouseMove(nFlags, point);
}
程序界面
打开程序
棋局进行中
棋局结束
最后,如果你对这个程序的算法有任何改进意见可以到我的github地址:https://github.com/Vaczzy/SimpleGobang。在这个地址中,你还可以看到对这个程序更详细的描述,我还贴上了我的邮箱地址,如有任何问题,你可以通过这个地址联系我 :)