头文件与宏定义
cpp
#include <graphics.h>
#include <conio.h>
graphics.h:EasyX 图形库,提供图形绘制功能(画线、画圆、显示文字等)。
conio.h:提供控制台输入输出函数(这里只是为了兼容性,实际用得少)。
cpp
#define NUM 15 // 棋盘边的格数
#define WIN_NUM 5 // 连续5个同色棋子胜利
NUM:棋盘一边有15条线,实际有14个格子,15个交叉点。
WIN_NUM:五子棋规则,连成5子获胜。
cpp
int pieceArr[NUM][NUM] = { 0 };
pieceArr:二维数组,表示棋盘上的状态。
0:没有棋子
1:黑棋
2:白棋
棋盘绘制部分
Draw_line() - 绘制棋盘格线
cpp
void Draw_line()
{
setlinecolor(BLACK);
for (int y = 20; y < 600; y += 40)
line(20, y, 580, y); // 画横线
for (int x = 20; x < 600; x += 40)
line(x, 20, x, 580); // 画竖线
}
每40像素画一条线,从 (20,20) 开始,到 (580,580) 结束。
保证棋盘大小和比例统一,方便后面落子。
Draw_point() - 绘制棋盘上的星位点(黑色小圆点)
cpp
void Draw_point()
{
setfillcolor(BLACK);
fillcircle(140, 140, 5);
fillcircle(460, 140, 5);
fillcircle(140, 460, 5);
fillcircle(460, 460, 5);
fillcircle(300, 300, 5);
}
在棋盘上五个标准位置绘制小圆点。
星位标志,有助于棋手定位。
棋子处理部分
Draw_piece(bool black, int x, int y) - 绘制棋子
cpp
void Draw_piece(bool black, int x, int y)
{
int i = x / 40; int j = y / 40;
if (black)
{
setfillcolor(BLACK);
pieceArr[i][j] = 1;
}
else
{
setfillcolor(WHITE);
pieceArr[i][j] = 2;
}
fillcircle(20 + i * 40, 20 + j * 40, 15);
}
根据鼠标点击的位置 (x,y),计算落在哪个格子上。
判断是黑棋还是白棋。
修改棋盘数组 pieceArr,记录落子状态。
画出棋子(半径15的圆)。
NicePos(int x, int y) - 判断点击位置是否合法
cpp
bool NicePos(int x, int y)
{
if (x < 20 || x > 580 || y < 20 || y > 580)
return false;
int i = x / 40;
int j = y / 40;
return pieceArr[i][j] == 0;
}
检查点击位置是否在棋盘区域内。
检查这个格子有没有被占用。
只有合法并且没落子的地方才能继续下棋。
判断胜负部分
GameOver(int x, int y) - 判断当前落子是否获胜
cpp
int GameOver(int x, int y)
{
x = x / 40;
y = y / 40;
int n = pieceArr[x][y];
}
首先把鼠标坐标转成棋盘数组坐标 (i,j)。然后进行四个方向的连续计数:
水平检查(左---右):
cpp
int count = 1;
for (int i = x - 1; i >= 0 && pieceArr[i][y] == n; i--) count++;
for (int i = x + 1; i < NUM && pieceArr[i][y] == n; i++) count++;
if (count >= WIN_NUM) return n;
垂直检查(上---下):
cpp
count = 1;
for (int j = y - 1; j >= 0 && pieceArr[x][j] == n; j--) count++;
for (int j = y + 1; j < NUM && pieceArr[x][j] == n; j++) count++;
if (count >= WIN_NUM) return n;
左上-右下斜线检查(45度):
cpp
count = 1;
for (int i = x - 1, j = y - 1; i >= 0 && j >= 0 && pieceArr[i][j] == n; i--, j--) count++;
for (int i = x + 1, j = y + 1; i < NUM && j < NUM && pieceArr[i][j] == n; i++, j++) count++;
if (count >= WIN_NUM) return n;
右上-左下斜线检查(135度):
cpp
count = 1;
for (int i = x + 1, j = y - 1; i < NUM && j >= 0 && pieceArr[i][j] == n; i++, j--) count++;
for (int i = x - 1, j = y + 1; i >= 0 && j < NUM && pieceArr[i][j] == n; i--, j++) count++;
if (count >= WIN_NUM) return n;
如果某个方向连续5个或更多相同棋子,就返回对应的棋子编号(1或者2),表示胜利。
如果四个方向都没有满足,返回0,表示游戏继续。
主函数 main()
cpp
int main()
{
initgraph(600, 600);
loadimage(NULL, _T("1.png"));
Draw_line();
Draw_point();
初始化绘图窗口 600x600。
加载一张背景图片(可选)。
画棋盘线和星位点。
游戏主循环
cpp
ExMessage m;
bool black = true;
bool gameOver = false;
while (!gameOver)
{
m = getmessage(EX_MOUSE);
if (m.message == WM_LBUTTONDOWN)
{
if (NicePos(m.x, m.y))
{
Draw_piece(black, m.x, m.y);
int result = GameOver(m.x, m.y);
监听鼠标左键点击。
判断落点是否合法。
绘制棋子,判断输赢。
如果胜利:
cpp
if (result == 1)
{
setbkmode(TRANSPARENT);
settextcolor(RED);
settextstyle(36, 0, _T("宋体"));
outtextxy(250, 300, _T("黑棋胜利!"));
FlushBatchDraw();
gameOver = true;
}
else if (result == 2)
{
setbkmode(TRANSPARENT);
settextcolor(RED);
settextstyle(36, 0, _T("宋体"));
outtextxy(250, 300, _T("白棋胜利!"));
FlushBatchDraw();
gameOver = true;
}
在屏幕上显示胜利信息。
cpp
black = !black;
}
}
}
轮流换手,黑白交替。
游戏结束后等待用户点击退出
cpp
while (true)
{
m = getmessage(EX_MOUSE);
if (m.message == WM_LBUTTONDOWN)
break;
}
closegraph();
return 0;
}
棋局结束后,等待鼠标点击任意处,再关闭窗口退出程序。
五子棋代码整体流程图
css
【开始】
↓
初始化窗口 (600x600),加载背景图
↓
绘制棋盘线 + 星位点
↓
设置黑棋先手
↓
【进入主循环】
↓
等待鼠标事件 (ExMessage)
↓
鼠标左键点击?
↓
是 → 检查点击点是否为空位 (NicePos)
↓
是 →
- 在点击位置绘制棋子 (Draw_piece)
- 更新棋盘数组 (pieceArr)
- 判断是否胜利 (GameOver)
↓
胜利?
↓
是 → 显示胜利信息,结束游戏
否 → 切换黑白方,继续
否 → 忽略本次点击
↓
【循环直到胜利】
↓
胜利后,等待一次鼠标点击
↓
退出程序 (closegraph)
↓
【结束】
点击落子与胜负判断小流程
css
鼠标左键点击
↓
NicePos 判断:
- 在棋盘内?
- 位置空闲?
↓
符合 →
- Draw_piece 画出棋子
- 更新 pieceArr 数组
- GameOver 检查四个方向 (横/竖/斜线)
- 连续5个?胜!
- 否则继续
- 切换黑白玩家
不符合 →
- 无操作,继续等待点击