一、 简介

本人最近用MFC制作了一个双人五子棋,实现了以下功能:
1.完全使用鼠标操作;
2.自动判断胜负;
3.悔棋;
4.保存和打开棋局。
下面,我与大家分享一下我的制作流程。
开发环境: Visual Studio 2019
完整代码点击此处下载。

二、程序编写

1. 创建资源文件

首先,创建双人五子棋解决方案,我的名称是GoBang。
创建对话框并调整对话框尺寸,我的尺寸是400*400。将对话框的标题改为“双人五子棋”,“边框”属性改为“对话框外框”,防止运行期间改变大小。

在对话框上放置6个Button控件,标题分别改为“开始游戏”(ID:IDC_START)“结束本局”(ID:IDC_ENDGAME)“退出”(ID:IDC_QUIT)“悔棋”(ID:IDC_REPENTANCE)“保存棋局”(ID:IDC_SAVE)“打开棋局”(ID:IDC_OPEN),将“结束本局”、“悔棋”和“保存”按钮设为最初禁用状态。
对话框到此设计完毕,棋盘我们会在后面使用代码绘制。最终的对话框效果如图所示:

然后,添加两个cursor光标资源,图案分别是一个黑棋和一个白棋。黑棋的ID是IDC_CURSOR1,白棋的ID是IDC_CURSOR2。

2. 判断胜负算法设计

双人五子棋由于是用户之间的对战,无需设计AI算法,所以算法很简单。它用到的主要算法只有一个:判断胜负。下面,我们就来设计判断胜负的算法。当然,下面是我自己的算法,肯定还有更好的算法,欢迎大家在评论区中为我指出缺点。
为了方便修改棋盘尺寸,我们定义了一个宏SIZE,它代表棋盘的行数和列数。

#define SIZE 15

下面我们开始创建变量。接下来的变量都放在GoBangDlg.h中作为对话框类的成员。首先,我们创建一个SIZE*SIZE的int二维数组(名为ChessBoard),这个数组就代表棋盘,每个元素的不同值代表棋盘交叉点的不同状态:-1为空,0为白,1为黑。再创建一个bool变量NowColor用来记录下一步棋的颜色,false(0)为白,true(1)为黑。接着创建一个bool变量IsPlaying记录是否正在游戏。代码如下:

bool IsPlaying;
bool NowColor;
int ChessBoard[SIZE][SIZE];//棋盘,-1为空,0为白,1为黑

由于计算机中数组下标是先行后列(先y轴后x轴),与我们平常的习惯(先列后行)不符,所以我们先创建一个函数转换这个差异。当然,这个函数也可以不写,但后面绘制棋子和判断鼠标位置的程序需要修改一下。

int CGoBangDlg::GetChessBoardColor(int nx, int ny)
{return ChessBoard[ny][nx];
}

接下来,我们开始创建算法的核心部分。我创建了一个函数,名为GetChessCount,这个名字很容易引起误解,这个函数的功能并不是获取棋盘上棋子的个数,而是获取指定坐标上的棋子在任意方向上相连的最大个数。举个例子,假如下面的棋盘中间的那一列最上方的棋子坐标为(5,5),那么GetChessCount(5,5)的值就为4(那个棋子横着连成了4个)。

该函数的实现代码如下:

int CGoBangDlg::GetChessCount(int nx, int ny)//获取指定棋子各个方向的同色棋子个数最大值
{int color = GetChessBoardColor(nx, ny);//获取指定点的棋子颜色if (color == -1)//空位return -1;int x = nx, y = ny;int m_max, count;while (--y >= 0 && GetChessBoardColor(x, y) == color);//获取这个棋子所在的y轴棋链中最下端的棋子坐标,注意行尾有分号,循环体什么也不做,y++并不是循环体y++;//由于上面的循环是先把y减1再判断,所以需要加1得到真正的坐标for (count = 1; (++y < SIZE) && (GetChessBoardColor(x, y) == color); count++);//获取y轴棋链的棋子个数,注意行尾有分号m_max = count;//y轴x = nx, y = ny;while (--x >= 0 && GetChessBoardColor(x, y) == color);x++;for (count = 1; ++x < SIZE && GetChessBoardColor(x, y) == color; count++);if (m_max < count)m_max = count;//x轴,代码意义同上x = nx, y = ny;while (x - 1 >= 0 && y - 1 >= 0 && GetChessBoardColor(x - 1, y - 1) == color)//这里由于是x-1而不是--x,所以行尾没有分号,x--,y--才是循环体,后面无需把x和y的值增加1,下同x--, y--;for (count = 1; x + 1 < SIZE && y + 1 < SIZE && GetChessBoardColor(x + 1, y + 1) == color; count++)x++, y++;if (m_max < count)m_max = count;//左下到右上,代码意义同上x = nx, y = ny;while (x - 1 >= 0 && y + 1 < SIZE && GetChessBoardColor(x - 1, y + 1) == color)x--, y++;for (count = 1; x + 1 < SIZE && y - 1 >= 0 && GetChessBoardColor(x + 1, y - 1) == color; count++)x++, y--;if (m_max < count)m_max = count;//左上到右下,代码意义同上return m_max;
}

接下来就简单了,直接调用GetChessBoardColor函数,就行了,我开始的想法是用一个函数遍历棋盘,判断是否有五子连线就行了,代码如下:

int CGoBangDlg::GetWinner()//获取赢家,-1无,0白,1黑
{for (int i = 0; i < SIZE; i++){for (int j = 0; j < SIZE; j++){int color = GetChessBoardColor(i, j);if (color != -1){if (GetChessCount(i, j) >= 5)return color;}}}return -1;
}

但后来我想到游戏过程中能够决定胜负的只有上一步下的棋子,所以其实只判断一个地方就行了,这会大大提高效率。改进后的代码如下:

 if (GetChessCount(order[index].x, order[index].y) >= 5)return NowColor;return -1;

至此,双人五子棋判断胜负算法部分设计完毕,之后我们只需要每走一步棋判断一次胜负就可以了。
除了基本的判断胜负,我还增加了一个悔棋功能。我们创建一个整形变量index,用于记录上一步是第几步棋,再创建一个类型为CPoint或POINT的数组,用来记录每一步棋的坐标。

int index;
CPoint order[SIZE*SIZE];

悔棋的具体算法在后面会讲解。

3.创建事件处理程序及绘图函数

让我们先从简单的入手吧。我们先处理窗口的WM_CLOSE消息,当窗口收到WM_CLOSE消息时,判断游戏是否在进行,如果在进行则弹出对话框询问是否要退出否则直接退出。代码如下:

void CGoBangDlg::OnClose()
{if (!IsPlaying || MessageBoxW(L"正在游戏中,确定要退出吗?", L"双人五子棋", MB_YESNO | MB_ICONQUESTION) == IDYES)CDialogEx::OnClose();
}

这里用到了一个C++逻辑或运算符基本规则,那就是如果第一个表达式成立,就不会计算第二个表达式。所以如果!IsPlaying(游戏不在进行),就不会 弹出对话框,而是直接关闭。
“退出”按钮的BN_CLICKED消息和WM_CLOSE消息的处理程序基本相同,这里就不再赘述了。代码如下:

void CGoBangDlg::OnBnClickedQuit()
{if (!IsPlaying || MessageBoxW(L"正在游戏中,确定要退出吗?", L"双人五子棋", MB_YESNO | MB_ICONQUESTION) == IDYES)EndDialog(0);
}

接着,我们修改一下GoBangDlg的DoDataExchange函数,进行数据初始化。代码很简单,就不再解释。代码如下:

void CGoBangDlg::DoDataExchange(CDataExchange* pDX)
{IsPlaying = false;for (int i = 0; i < SIZE; i++){for (int j = 0; j < SIZE; j++){ChessBoard[i][j] = -1;}}//初始化棋盘CDialogEx::DoDataExchange(pDX);
}

然后,我们要修改WM_PAINT消息绘制棋盘和棋子。代码如下:

void CGoBangDlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CPaintDC dc(this);CPen pen(PS_SOLID, 2, RGB(0, 0, 0));dc.SelectObject(pen);for (int i = 0; i < SIZE; i++){dc.MoveTo(50, 50 + i * 50);dc.LineTo(750, 50 + i * 50);}//绘制棋盘横线for (int i = 0; i < SIZE; i++){dc.MoveTo(50 + i * 50, 50);dc.LineTo(50 + i * 50, 750);}//绘制棋盘竖线for (int nx = 0; nx < SIZE; nx++)//遍历棋盘,绘制每一个棋子{for (int ny = 0; ny < SIZE; ny++){int color = GetChessBoardColor(nx, ny);if (color == 0)//白棋{CBrush brush_w(RGB(255, 255, 255));const CPoint o(50 * nx + 50, 50 * ny + 50);//圆心dc.SelectObject(brush_w);dc.Ellipse(o.x - 15, o.y - 15, o.x + 15, o.y + 15);}else if (color == 1)//黑棋{CBrush brush_b(RGB(0, 0, 0));const CPoint o(50 * nx + 50, 50 * ny + 50);//圆心dc.SelectObject(brush_b);dc.Ellipse(o.x - 15, o.y - 15, o.x + 15, o.y + 15);}}}}
}

代码应该不难理解,用的是MFC的绘图工具,和GDI绘图类似,非常方便,不需要担心内存泄漏等问题,构造函数和析构函数会自动处理绘图对象的创建和删除。但有些MFC或Windows API开发经验的人可能会注意到一个问题:我用的是CPaintDC,相当于Windows API中的BeginPaint函数,这样只会绘制一次,绘制结束后不会再收到WM_PAINT消息,下棋后无法正常显示棋子。这个问题有道理。因为五子棋不需要一直重绘已经存在的棋子,如果一直重绘已经存在的棋子会大幅度降低程序性能,所以我在SetChessBoardColor函数中会绘制新下的棋子,已经绘制的棋子和棋盘不会改变,这个函数下面会讲到。这里之所以还添加绘制棋子的程序,是因为两种情况:
(1)游戏过程中,窗口被移出屏幕边缘或被最小化,恢复正常时窗口会收到WM_PAINT消息,如果不绘制棋子,则无法正常显示棋盘上已经存在的棋子。
(2)悔棋时由于无法直接擦除已经下了的棋子,需要调用Invalidate函数重新绘制,如果不绘制棋子,则无法正常显示棋盘上已经存在的棋子。

既然提到了SetChessBoardColor函数,那我们先来看看它的代码。这个函数不仅能修改ChessBoard,还能在屏幕上绘制出棋子,这样就不用重绘整个棋盘了。

void CGoBangDlg::SetChessBoardColor(int nx, int ny, int color)
{ChessBoard[ny][nx] = color;CDC* dc = this->GetDC();CPen pen(PS_SOLID, 2, RGB(0, 0, 0));dc->SelectObject(pen);if (color == 0)//白棋{CBrush brush_w(RGB(255, 255, 255));const CPoint o(50 * nx + 50, 50 * ny + 50);//圆心dc->SelectObject(brush_w);dc->Ellipse(o.x - 15, o.y - 15, o.x + 15, o.y + 15);}else if (color == 1)//黑棋{CBrush brush_b(RGB(0, 0, 0));const CPoint o(50 * nx + 50, 50 * ny + 50);//圆心dc->SelectObject(brush_b);dc->Ellipse(o.x - 15, o.y - 15, o.x + 15, o.y + 15);}else//清除该坐标棋子,需要重绘,用于悔棋{RECT rect;GetClientRect(&rect);InvalidateRect(&rect);}
}

然后是CleanChessBoard函数,该函数清空ChessBoard数组和屏幕上的棋子。代码如下:

void CGoBangDlg::CleanChessBoard()
{for (int i = 0; i < SIZE; i++){for (int j = 0; j < SIZE; j++){ChessBoard[i][j] = -1;}}Invalidate();//刷新
}

然后我们来创建EndGame函数,它的功能是结束游戏。代码如下:

void CGoBangDlg::EndGame()
{CleanChessBoard();IsPlaying = false;index = -1;GetDlgItem(IDC_START)->SetWindowTextW(L"开始游戏");GetDlgItem(IDC_ENDGAME)->EnableWindow(FALSE);GetDlgItem(IDC_REPENTANCE)->EnableWindow(FALSE);GetDlgItem(IDC_SAVE)->EnableWindow(FALSE);
}

接下来,我们创建“开始游戏”按钮的BN_CLICKED消息。由于开始游戏与重玩的代码完全相同,所以我们就不再创建重玩按钮,而是通过修改“开始游戏”按钮的窗口标题实现。代码如下:

void CGoBangDlg::OnBnClickedStart()
{if (IsPlaying && MessageBoxW(L"确定要重玩吗?", L"双人五子棋", MB_YESNO | MB_ICONQUESTION) == IDNO)return;GetDlgItem(IDC_START)->SetWindowTextW(L"重玩");IsPlaying = true;NowColor = 1;//黑先index = -1;GetDlgItem(IDC_ENDGAME)->EnableWindow(TRUE);GetDlgItem(IDC_REPENTANCE)->EnableWindow(FALSE);GetDlgItem(IDC_SAVE)->EnableWindow(TRUE);CleanChessBoard();
}

这里用到了一个C++逻辑与运算符基本规则,那就是如果第一个表达式不成立,就不会计算第二个表达式。所以如果IsPlaying(游戏在进行)不成立,就不会 弹出对话框,而是直接进行下面的代码。
接着,我们创建“结束本局”的BN_CLICKED消息处理程序。因为我们以前已经写了EndGame函数,这里直接调用就行了。代码如下:

void CGoBangDlg::OnBnClickedEndgame()
{if (MessageBoxW(L"确定要结束本局吗?", L"双人五子棋", MB_YESNO | MB_ICONQUESTION) == IDYES)EndGame();
}

然后是对话框的WM_SETCURSOR消息处理程序。这个函数设置鼠标光标的状态,决定鼠标是黑子、白子还是普通。代码如下:

BOOL CGoBangDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{POINT point;GetCursorPos(&point);ScreenToClient(&point);if (!IsPlaying || point.x < 40 || point.x>760 || point.y < 40 || point.y>760)//判断鼠标当前位置是否在棋盘里return CDialogEx::OnSetCursor(pWnd, nHitTest, message);if (NowColor == 1)//黑棋SetCursor(LoadCursorW(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDC_CURSOR1)));elseSetCursor(LoadCursorW(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDC_CURSOR2)));return TRUE;
}

现在,我们要创建一个极其重要的消息处理函数——响应鼠标左键松开的消息处理函数,其中point是鼠标的坐标(以客户区为参照系)。这个函数的功能是在鼠标单击处放置棋子并判断胜负。代码如下:

void CGoBangDlg::OnLButtonUp(UINT nFlags, CPoint point)
{if (!IsPlaying || point.x < 40 || point.x>760 || point.y < 40 || point.y>760)//判断鼠标是否在棋盘里return;int x = int(round(point.x / 50.0) - 1);//round是四舍五入函数int y = int(round(point.y / 50.0) - 1);//将鼠标坐标转为数组下标if (GetChessBoardColor(x, y) != -1)//如果已有棋子return;SetChessBoardColor(x, y, NowColor);index++;order[index].x = x;order[index].y = y;//记录上一步的坐标,用于悔棋GetDlgItem(IDC_REPENTANCE)->EnableWindow(index > -1);//如果可以悔棋,取消禁用“悔棋”按钮,否则禁用“悔棋”按钮SendMessage(WM_SETCURSOR);//刷新鼠标//以上为放置棋子int winner = GetWinner();int count = 0;for (int i = 0; i < SIZE; i++){for (int j = 0; j < SIZE; j++){if (ChessBoard[i][j] != -1)count++;}}if (winner != -1||count == SIZE * SIZE){if (winner == 0)MessageBoxW(L"白棋胜利!", L"双人五子棋", MB_OK | MB_ICONINFORMATION);else if (winner == 1)MessageBoxW(L"黑棋胜利!", L"双人五子棋", MB_OK | MB_ICONINFORMATION);elseMessageBoxW(L"平局!", L"双人五子棋", MB_OK | MB_ICONINFORMATION);EndGame();return;}//判断胜负NowColor = (!NowColor);
}

最后的判断胜负要注意,五子棋除了一方打败另一方,还有一种情况:平局。平局也就是棋盘所有交叉点都下满了,但还没有连成五个子。这时候,我们必须结束游戏,否则棋局无法进行。

最后,我们创建悔棋按钮被按下的消息处理函数。代码如下:

void CGoBangDlg::OnBnClickedRepentance()
{SetChessBoardColor(order[index].x, order[index].y, -1);//清除上一步棋index--;GetDlgItem(IDC_REPENTANCE)->EnableWindow(index > -1);NowColor = (!NowColor);//改变棋子颜色
}

至此,双人五子棋的消息处理部分已经完成,保存和打开的函数我会单独介绍。

4.学习创建一种文件格式——打开和保存算法

任何一个可以存储信息的软件都有一种文件格式,如word的格式是doc或docx,powerpoint的格式是ppt或pptx等。如果你用记事本打开docx/pptx文档,会发现很简短的一篇文档用记事本打开都会变得很长,这是因为word在保存文字的同时还保存了很多其它属性,如字体、字号、行间距等等。当保存文件时,word会自动将用户输入的文件转化为docx格式,打开文件时又会按自己的文件格式读取文件,并转化为各种属性,这样就可以还原保存时的样子了。五子棋程序也不例外,为了保存完整的棋局状态,我们需要把内存中所有与棋局有关的变量都复制到磁盘中,这就需要我们专门设计一种文件格式。我设计的五子棋文件格式如下:
1.扩展名:gob。
2.文件由多个数字组成,保存了程序运行时的所有变量。
3.第1到第SIZE*SIZE(225)个数字:记录棋盘上每个交叉点的状态。(ChessBoard)
4.第SIZE*SIZE+1(226)个数字:记录下一步是哪一方走。(NowColor)
5.第SIZE*SIZE+2(227)个数字:记录已经走了多少步棋,供悔棋功能用。(index)
6.第SIZE*SIZE+3(228)到第(SIZE*SIZE+3+第226个数字*2)个数字:
每两个数为一组,记录每一步棋的x坐标和y坐标。(order)

例如:
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 -1 -1 -1
-1 -1 -1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 1 0 1 1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 0 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1
-1 -1 -1 0 -1 -1 -1 -1 0 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
1
13
7 7
6 8
5 7
5 6
3 5
3 4
6 2
11 3
10 9
3 10
3 9
8 10
8 7
6 7
这就是一个完整的gob文件的内容。
下面,我们开始创建保存算法,这个算法用到了ofstream类。代码如下:

void CGoBangDlg::OnBnClickedSave()
{CFileDialog filedlg(FALSE);filedlg.m_ofn.lpstrFilter = L"五子棋文件(*.gob)\0*.gob\0\0";if (filedlg.DoModal() != IDOK)return;CString filename = filedlg.GetPathName();if (filedlg.GetFileExt() == L"")//如果用户没有输入扩展名filename += ".gob";std::ofstream outfile;outfile.open(CStringA(filename));if(!outfile){MessageBoxW(L"保存失败!", L"双人五子棋", MB_OK | MB_ICONERROR);return;}for (int y = 0; y < 15; y++){for (int x = 0; x < 15; x++){outfile << GetChessBoardColor(x, y) << '\0';}outfile << '\r';}//输出ChessBoard数组outfile <<NowColor<<'\r'<< index << '\r';for (int i = 0; i <= index; i++)outfile << order[i].x << '\0' << order[i].y << '\r';outfile.close();//输出order数组MessageBoxW(L"保存成功!", L"双人五子棋", MB_OK | MB_ICONINFORMATION);
}

保存文件的算法比较简单,但读取文件就要麻烦一些了。我们来看看它的代码:

void CGoBangDlg::OnBnClickedOpen()
{CFileDialog filedlg(TRUE);filedlg.m_ofn.lpstrFilter = L"五子棋文件(*.gob)\0*.gob\0\0";if (filedlg.DoModal() != IDOK)return;CString filename = filedlg.GetPathName();if (filedlg.GetFileExt() == L"")filename += ".gob";std::ifstream infile;infile.open(CStringA(filename));if (!infile){MessageBoxW(L"打开失败!", L"双人五子棋", MB_OK | MB_ICONERROR);return;}for (int y = 0; y < 15; y++){for (int x = 0; x < 15; x++){int t;infile >> t;infile.seekg(infile.tellg().operator+(1));ChessBoard[y][x] = t;//因为保存文件已经用了GetChessBoardColor函数,文件中的数字是正常顺序,不能使用SetChessBoardColor函数。而且,SetChessBoardColor遇到-1就会刷新棋盘,性能不好。}}Invalidate();//绘制棋盘和棋子infile >> NowColor;infile.seekg(infile.tellg().operator+(1));infile >> index;for (int i = 0; i <= index; i++){infile.seekg(infile.tellg().operator+(1));infile >> order[i].x;infile.seekg(infile.tellg().operator+(1));infile>> order[i].y;}infile.close();GetDlgItem(IDC_START)->SetWindowTextW(L"重玩");GetDlgItem(IDC_ENDGAME)->EnableWindow(TRUE);GetDlgItem(IDC_REPENTANCE)->EnableWindow(index > 0);GetDlgItem(IDC_SAVE)->EnableWindow(TRUE);IsPlaying = true;
}

这里有一点要注意,那就是每读完一个数据就会有一行

infile.seekg(infile.tellg().operator+(1));

把指针向后移动一个字节。

到现在,双人五子棋已经完成,我们可以邀请家人和朋友一起来玩了!这个程序我调试过很多次,目前没有发现bug,如果有人发现了漏洞或有更好的意见,欢迎大家在评论区提出。

三、程序截图

初始窗口状态:

游戏中:

悔棋功能:

某方获胜:

保存棋局:

打开棋局:

退出:

MFC双人五子棋(VS2019)相关推荐

  1. 基于opencv与MFC实现的双人五子棋

    之所以给他取名双人五子棋,是因为这个程序实现的功能并不具备AI(人机对弈)功能,只能由两个玩家自己操作,棋盘显示部分是基于opencv实现的. 其实只是一个很简单的程序,如果说有些难度的话,就是在棋盘 ...

  2. 双人五子棋对战(需要EasyX图像库)

    实训要做项目呐.天天坐在电脑面前累死了.最近题刷的少.大多数都挺水.就不挨个编辑发上来了.发发白天写的项目吧.可能好几天更一下.实训结束恢复正常. 这个游戏需要EasyX的图像库.有兴趣的可以下一个图 ...

  3. C语言实践——双人五子棋(简易版)

    双人五子棋 前言 一.五子棋的元素 二.五子棋规则(简单) 三.主要功能的设计 1.头文件和宏定义 2.初始化棋盘 3.打印棋盘 4.判断输赢 5.辅助函数 6.主函数 四.程序结果展示 前言 五子棋 ...

  4. c++ 双人五子棋(可直接复制)

    今天,我给大家带来一个五子棋的代码,希望大家喜欢. 下面是代码: #include <iostream> #include <conio.h> using namespace ...

  5. MFC实现五子棋游戏

    MFC制作五子棋 一.    结果展示: 二.    需求分析: 1)      五子棋游戏逻辑分析: 五子棋游戏规则简单易懂:棋盘大小为15*15:棋子分为黑白两色:若任意一方在"米字格& ...

  6. Win32 双人五子棋

    Win32 双人五子棋思路 一.实现要求: 绘制一个14乘14的棋盘格,然后黑白两种棋子依次下棋,会判断谁先连成5子. 二.运行环境: Visual C++6.0 基于Windows应用程序的基本框架 ...

  7. 使用MFC实现五子棋

    本篇博文介绍使用MFC实现五子棋游戏,实现了五子棋的对弈.菜单栏.工具栏以及状态栏. 主界面 菜单栏 工具栏 底部状态栏 下面是核心代码,落子之后判断胜负: void CMy05gobangView: ...

  8. 基于MFC的五子棋(详细介绍,适合初学者)

    基于MFC的五子棋游戏 开发工具:VC++ 1. 建立界面,即先建立一个棋盘 1.1新建一个MFC工程 1.2往这个工程里面添加一些资源,里面的内容暂时可以先不管,等到后面我们再往里面添加东西 1.3 ...

  9. C++实现图形界面双人五子棋游戏

    C++实现图形界面双人五子棋游戏 设计思路 定义一个Chess类,用16*16的二维数组的来表示一方棋手在棋局上的落子状态. 通过控制键盘←↑→↓来选择落点,getch()函数可获得用户的键盘输入,用 ...

  10. C语言实践——双人五子棋(进阶版)

    双人五子棋 前言 一.棋盘的美化 二.棋子的美化 三.棋盘的打印 四.控制台修改颜色 五.五子棋源代码 前言  上一篇文章讲了如何用C语言写一个简易的双人五子棋小游戏,但是存在一些缺陷,比如棋盘太&q ...

最新文章

  1. 数据治理(Data Governance)
  2. 安防AI芯片“战国时代” 谁能稳坐钓鱼台?
  3. 多分类神经网络与原子核
  4. id文本框适应文字_Indesign中对同一行文字进行分行缩排的操作方法
  5. OpenGL计算着色器
  6. VS Code配置Java万能环境
  7. Oracle 11g 新特性 -- 自适应游标共享(Adaptive Cursor Sharing: ACS) 说明
  8. 工具类TestTools
  9. MySQL中 limit和offset用法
  10. yolov3中yolov3-voc.cfg文件中参数理解
  11. [经验] 系统封装常见问题大总结(非官方)
  12. 数据交换方式(电路交换、数据报交换、分组交换)
  13. nginx 域名重定向跳转至另一个域名
  14. C++ Opencv中Mat的操作
  15. JTA Transaction
  16. 电子通讯秤对接配置详解!
  17. SystemUI深度裁剪
  18. STM32入门之点亮LED灯
  19. 3D小人 思考/问号 表情图 png格式
  20. 500多款免费商用字体,让你的设计如虎添翼!

热门文章

  1. 基于Python实现的机器人自动走迷宫
  2. Android自定义LayoutManager第十一式之飞龙在天
  3. 浅显易懂的经济学常识
  4. Java实现系统统一对外开放网关入口设计
  5. 如何打开管理员命令提示符窗口?
  6. win10虚拟机dhcp服务器设置,win10 配置dhcp服务器设置
  7. Mybatis源码-cursor(游标)
  8. 如何一次将蓝牙耳机连接到多个设备
  9. python字典包含指定键_筛选python字典中键包含特定字符串的项
  10. USB、MiniUSB、MicroUSB