1新建工程
项目->VC++->MFC->MFC应用程序->输入名称->单文档->Window套接字->完成
2资源编辑
视图->其他窗口->资源试图
添加黑白位图以表示棋盘上面的棋子
IDB_BLACK
IDB_WHITE
黑白鼠标Cursor以替换当前鼠标
IDC_CURSOR1
IDC_CURSOR2
黑白图标Icon以显示在状态栏供以提示
IDI_BLACK
IDI_WHITE
3构造函数
//在MainFrm.h文件里面,将“// 控件条嵌入成员”前面的代码改为“public: CStatusBar m_wndStatusBar;”
//然后在五子棋测试View.h里面添加变量函数
//两个鼠标
HCURSOR hcursorwhite;
HCURSOR hcursorblack;
//棋盘数组
int wzq[19][19];
//colorwhite TRUE时baiqi下
bool colorwhite;
//棋子位图
CBitmap m_bmblack;
CBitmap m_bmwhite;
4棋盘大小设置
由于我们的棋盘大小是一定的,不能改变大小的,是应该符合要求的,在如下函数(MainFrm.cpp文件中)添加设置窗口大小的语句;
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CMDIFrameWndEx::PreCreateWindow(cs) )
return FALSE;
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
cs.dwExStyle = cs.dwExStyle|WS_EX_TOPMOST;
cs.style = WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;
//设置窗口的大小
cs.cx = 450;
cs.cy = 500;
return TRUE;
}
5初始化变量
在构造函数(五子棋测试View.cpp文件中)里面添加初始代码
C五子棋测试View::C五子棋测试View()
{
// TODO: 在此处添加构造代码
//load鼠标图像和棋子位图
hcursorblack = AfxGetApp()->LoadCursor(IDC_BLACK);
hcursorwhite = AfxGetApp()->LoadCursor(IDC_WHITE);
m_bmwhite.LoadBitmap(IDB_WHITE);
m_bmblack.LoadBitmap(IDB_BLACK);
//清理棋盘
//数组值为0时表示没有棋子
for (int i = 0; i < 19; i++)
{
for (int j = 0; j < 19; j++)
{
wzq[i][j] = 0;
}
}
//白棋先下
colorwhite = true;
}
6画棋盘
在OnDraw(CDC* pDC)函数中画棋盘,由于游戏中有可能重画棋盘,而那时棋盘上面有棋子,所以,我们在这个函数里面必须有画棋子的语句
数组的值为1表示白棋,-1表示黑棋
void C五子棋测试View::OnDraw(CDC* pDC)
{
C五子棋测试Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CBrush mybrush1;
mybrush1.CreateSolidBrush(RGB(192,192,192));
CRect myrect1(0,0,1200,800);
pDC->FillRect(myrect1,&mybrush1);
//画棋盘框线
CPen mypen;
CPen* myoldPen;
mypen.CreatePen(PS_SOLID,1,RGB(0,0,0));
myoldPen = pDC->SelectObject(&mypen);
for (int i = 0; i < 19; i++)
{
pDC->MoveTo(40,40+i*20);
pDC->LineTo(400,40+i*20);
pDC->MoveTo(40+i*20,40);
pDC->LineTo(40+i*20,400);
}
//重画时显示的棋子
CDC Dc;
if (Dc.CreateCompatibleDC(pDC) == FALSE)
{
AfxMessageBox(_T("Can't creat DC"));
}
for (int n = 0; n < 19; n++)
{
for (int m = 0; m < 19; m++)
{
if (wzq[n][m] == 1)
{
//显示白棋
Dc.SelectObject(m_bmwhite);
pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY);
}
else if(wzq[n][m] == -1)
{
//显示黑棋
Dc.SelectObject(m_bmblack);
pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY);
}
}
}
}
7设置鼠标
棋盘画好了,下来就是下棋,但是鼠标并没有像我们上面所说的那样变成白棋
添加消息函数:类视图-> C五子棋测试View ->右击->类向导->消息->WM_SETCURSOR->OnSetCursor
BOOL C五子棋测试View::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (nHitTest == HTCLIENT)
{
//白棋下,显示白棋鼠标
if (colorwhite)
{
//调用主框架里面的状态栏
CMainFrame*pFrm=(CMainFrame*)AfxGetApp()->m_pMainWnd;
CStatusBar*pStatus=&pFrm->m_wndStatusBar;
if (pStatus)
{
pStatus->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDB_WHITE));
pStatus->SetPaneText(0,_T("白棋下"));
}
SetCursor(hcursorwhite);
}
//显示黑棋鼠标
else
{
SetCursor(hcursorblack);
CMainFrame*pFrm = (CMainFrame*)AfxGetApp()->m_pMainWnd;
CStatusBar*pStatus = &pFrm->m_wndStatusBar;
if (pStatus)
{
//显示图像
pStatus->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDB_WHITE));
//显示文字
pStatus->SetPaneText(0,_T("黑棋下"));
}
}
return 1;
}
return CView::OnSetCursor(pWnd, nHitTest, message);
}
8下棋操作
这就涉及到OnLButtonDown(UINT nFlags,CPoint point)和OnLButtonUp(UINT nFlags,CPoint point)两个函数了,要用一个还是两个?用down函数是在鼠标按下时放下棋子,可是,要是我们按下后意识到按错了怎么办,那就改用up函数,表示当鼠标键松开时放下棋子
添加消息函数:类视图-> C五子棋测试View ->右击->类向导->消息->WM_LBUTTONUP->OnLButtonUp
void C五子棋测试View::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
// TODO: 在此添加消息处理程序代码和/或调用默认值
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDC*pDC = GetDC();
CDC Dc;
if (Dc.CreateCompatibleDC(pDC) == FALSE)
AfxMessageBox(_T("Can't create DC"));
//是否在棋盘内
if (point.x > 30&&point.x < 410&&point.y > 30&&point.y <410)
{
int px = (point.x-30)/20;
int py = (point.y-30)/20;
//是否已经有棋子
if (colorwhite&&wzq
[px][py] == 0)
{
Dc.SelectObject(m_bmwhite);
pDC->BitBlt(px*20+32,py*20+32,160,160,&Dc,0,0,SRCCOPY);
//表示白棋存在
wzq[px][py] = 1;
//检查是否结束
over(point);
//换黑棋下
colorwhite = false;
}
else if(wzq[px][py] == 0)
{
Dc.SelectObject(m_bmblack);
pDC->BitBlt(px*20+32,py*20+32,160,160,&Dc,0,0,SRCCOPY);
//表示黑棋存在
wzq[px][py] = -1;
//检查是否结束
over(point);
//换白棋下
colorwhite = true;
}
}
CView::OnLButtonUp(nFlags, point);
}
9是否结束
用over()函数判断是否结束,是则结束并重新开始,否则接着把鼠标变成对方棋子,表示对方下棋
Over()函数利用刚下棋的位置为中心,检查它各个方向上的连续五个棋子是否同色,是则结束并重新开始
利用连续五个相同的棋子的值相加,去过他们的绝对值为5,则说明是同色
添加函数:类视图-> C五子棋测试View ->右击->添加->添加函数
void C五子棋测试View::over(CPoint point) {
//获取鼠标指向数组位置,即中心位置
int x = (point.x - 30) / 20; int y = (point.y - 30) / 20;
//计算开始判断的坐标 xx,yy
int xx,yy;
if (x < 4)
xx = 0;
else xx = x - 4; if (y < 4)
yy = 0;
else
yy = y - 4;
int i, j, a;
//横向判断
for (i = xx; i < 15; i++)
{
a = 0;
for (j = i; j < i + 5; j++)
{
a = a + wzq[j][y];
//五个都是白棋
if (a == 5)
{
AfxMessageBox(_T("白棋胜!"));
//重新开始
OnStart();
return;
}
//五个都是黑棋
if (a == -5)
{
AfxMessageBox(_T("黑棋胜!"));
OnStart();
return;
}
}
}
//竖向判断
for (i = yy; i < 15; i++)
{
a = 0;
for (j = i; j < i + 5; j++)
{
a = a + wzq[x][j];
if (a == 5)
{
AfxMessageBox(_T("白棋胜!"));
OnStart();
return;
}
if (a == -5)
{
AfxMessageBox(_T("黑棋胜!"));
OnStart();
return;
}
}
}
//向右下角
//判断起点位置
if(x(18-x))
{
if (x > 13)
{
yy = y - (18 - x);
xx = 18;
}
else
{
yy = y - 4;
xx = x + 4;
}
}
else
{
if (y < 5)
{
xx = x + y;
yy = 0;
}
else
{
yy = y - 4;
xx = x + 4;
}
}
over = 0;
do
{
a = 0;
for (i = 0; i < 5; i++)
{
if ((xx - i) >= 0 || (yy + i) < 19)
{
a = a + wzq[xx - i][yy + i];
if (a == 5)
{
AfxMessageBox(_T("白棋胜!"));
OnStart();
return;
}
if (a == -5)
{
AfxMessageBox(_T("黑棋胜!"));
OnStart();
return;
}
}
//到了边界
else
over=1;
}
xx -= 1;
yy += 1;
} while (over == 0);
}
10清理棋盘
Onstart()函数用来清理棋盘,从新初始化棋盘,为下一盘棋做准备
添加函数:类视图-> C五子棋测试View ->右击->添加->添加函数
void C五子棋测试View::OnStart()
{
//清理棋盘
//数组值为0表示没有棋子
for (int i = 0; i < 19; i++)
{
for (int j = 0; j < 19; j++)
{
wzq[i][j] = 0;
}
//白棋先下
colorwhite = true;
Invalidate();
}
}
4、 运行调试与分析讨论
下面是小程序运行结果的主窗口,如图,包括棋盘和其他各个操作。开局是白色棋子先落棋,所以,鼠标呈现白色棋子样式。由于图片是截屏出来的,所以并未看到此效果。
下图是游戏中的状态,当落下棋子后,会进入over函数中,判断是否可以结束。如果结束。则清空棋盘,重新开始。如果不结束,则把鼠标变成对方的棋子,表示对方下棋。如此循环下去,直到游戏结束
下图是游戏结束的状态,当某一方棋子获胜后,会弹出一个窗口,显示某一方获胜。在分出胜负后,可以选择点击结束按钮,开始新的一局。
出现的问题:在调试过程中曾出现过棋盘显示出来了,但是无法落棋子的bug。究其原因还是因为在void C五子棋测试View::OnLButtonUp(UINT nFlags, CPoint point)函数中的
if (point.x > 30&&point.x < 410&&point.y > 30&&point.y <410)判断语句中将point.y <410写成了point.y <40,导致落棋位置找不到,无法在棋盘上显示。
缺陷:第一是没有保存功能,第二是只有人人对战,第三是下棋时没有悔棋功能。