该项目适合新手拿来练习,所用的知识点不是很多,代码部分只有100多行。主要是图形化界面的应用,本游戏实现了人人对战,可以和好朋友来进行对弈。
在15×15的棋盘上,玩家轮流落子(黑子先手),尝试在水平、垂直或对角线方向上形成连续的五子,以获得胜利。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
int num =1;//-1表示白子,1表示黑子
HWND hwnd1= NULL;
//定义一个二维数组存放数据
int piece[15][15];
//函数声明
void draw_line();
void draw_point();
void draw_piece(int m, int n);
void initpiece();
int change_piece(int x, int y);
int check(int x, int y);
int rules();
void reset_game();
printf
和 scanf
。初始化操作:
printf
和 scanf
分别输入执黑棋和执白棋的玩家姓名。initgraph(650, 450)
初始化图形界面,创建窗口大小为 650x450 像素的游戏窗口。游戏主循环 (while (1)
循环):
reset_game()
函数用于初始化棋盘和游戏状态,清空画面并绘制棋盘。GetMouseMsg()
用于获取鼠标消息,检测鼠标左键按下事件(WM_LBUTTONDOWN
),然后调用 draw_piece(m.x, m.y)
在棋盘上落子。rules()
函数检测当前游戏状态,判断是否有玩家获胜。如果有玩家获胜,弹出消息框显示胜利者,然后跳出当前游戏循环。游戏结束和重新开始:
MessageBox
函数)。关闭程序:
closegraph()
函数关闭图形界面,释放资源,并返回 0 终止程序运行。棋盘绘制和棋子落子:
draw_line()
和 draw_point()
函数用于绘制棋盘的网格线和特殊点。draw_piece()
函数根据当前落子的位置绘制相应颜色的棋子,实现了落子效果和交替玩家回合。游戏规则和胜利判断:
check()
函数用于检查某个位置落子后是否达成五子连珠的条件。rules()
函数在每一步落子后调用,用于判断是否有玩家胜利。
int main()
{
char one[5];
char two[5];
printf("请输入执黑棋(先手)的姓名:");
scanf("%s", one);
printf("请输入执白棋(后手)的姓名:");
scanf("%s", two);
hwnd1= initgraph(650, 450);
while (1)
{
MOUSEMSG m;
reset_game();
while (1)
{
m = GetMouseMsg();
//如果鼠标左健按下
if (m.uMsg == WM_LBUTTONDOWN) draw_piece(m.x, m.y);
if (rules() == 1)
{
if (num == 1)
{
MessageBox(hwnd1, "白棋获胜", "胜利", MB_OK);
}
else
{
MessageBox(hwnd1, "黑棋获胜", "胜利", MB_OK);
}
break;
}
}
int a = MessageBox(hwnd1, "是否要重新开始", "重新开始", MB_YESNO);
if (a != IDYES)
{
break;
}
}
closegraph();
return 0;
}
setlinecolor(color)
:设置画线的颜色。RGB(rand() % 255, rand() % 255, rand() % 255)
生成一个随机的 RGB 颜色,使得每次绘制的棋盘颜色都不同。line(x1, y1, x2, y2)
:画线函数,用于绘制棋盘的网格线。在这里,通过循环绘制多条水平和垂直线,形成棋盘的格子。for (int i = 15; i <= 450; i+=30)
:循环变量 i
从 15 开始,每次增加 30,绘制棋盘的行和列。line(i, 15, i, 435)
和 line(15, i, 435, i)
分别绘制垂直和水平方向上的线条。RGB(rand() % 255, rand() % 255, rand() % 255)
:使用 rand()
函数生成 0 到 254 之间的随机整数,作为 RGB 颜色的值。这种方法可以在每次绘制时为棋盘赋予随机的颜色,增加视觉上的多样性和趣味性。//画棋盘
void draw_line()
{
setlinecolor(RGB(rand() % 255, rand() % 255, rand() % 255));
for (int i = 15; i <= 450; i+=30)
{
line(i, 15, i, 435);
line(15, i, 435, i);
}
}
填充函数:
setfillcolor(color)
:设置填充颜色。RGB(rand() % 255, rand() % 255, rand() % 255)
生成一个随机的 RGB 颜色,用于每个棋子的填充颜色设置。fillcircle(x, y, radius)
:绘制实心圆函数。在这里,用于绘制五子棋棋盘上的五个棋子的位置。具体绘制位置:
fillcircle(4*30-15, 4*30-15, 3)
:绘制一个半径为 3 的实心圆,位于棋盘上第 4 列第 4 行的位置。fillcircle(4*30-15, 12*30-15, 3)
:绘制一个半径为 3 的实心圆,位于棋盘上第 4 列第 12 行的位置。fillcircle(8*30-15, 8*30-15, 3)
:绘制一个半径为 3 的实心圆,位于棋盘上第 8 列第 8 行的位置。fillcircle(12*30-15, 4*30-15, 3)
:绘制一个半径为 3 的实心圆,位于棋盘上第 12 列第 4 行的位置。fillcircle(12*30-15, 12*30-15, 3)
:绘制一个半径为 3 的实心圆,位于棋盘上第 12 列第 12 行的位置。fillcircle()
函数在指定的棋盘位置绘制实心圆,表示五子棋中的黑子或白子。//画点
void draw_point()
{
setfillcolor(RGB(rand() % 255, rand() % 255, rand() % 255));
fillcircle(4*30-15,4*30-15,3);
fillcircle(4*30-15,12*30-15,3);
fillcircle(8*30-15,8*30-15,3);
fillcircle(12*30-15,4*30-15,3);
fillcircle(12*30-15,12*30-15,3);
}
void draw_piece(int m, int n);
这是一个名为 draw_piece
的函数,接受两个整数参数 m
和 n
。这些参数是棋子的位置坐标。
if (num == -1) setfillcolor(WHITE); else if (num == 1) setfillcolor(BLACK);
根据变量 num
的值设置填充颜色。如果 num
的值为 -1
,填充颜色设置为白色;如果 num
的值为 1
,填充颜色设置为黑色。
int x, y; x = m / 30; y = n / 30;
根据传入的参数 m
和 n
计算棋子在棋盘上的位置。假设每个格子的大小为 30x30,通过整除操作来确定棋子所在的格子。
change_piece
函数:if (change_piece(x, y) == 0) return;
调用 change_piece
函数,传入棋子的格子坐标 (x, y)
。如果 change_piece
函数返回值为 0
,则退出当前函数,不绘制棋子。
fillcircle(m - (m % 30) + 15, n - (n % 30) + 15, 13);
使用 fillcircle
函数在指定位置绘制一个半径为 13 的实心圆。m - (m % 30) + 15
和 n - (n % 30) + 15
确保圆心在格子的中心位置。
num
的值:num *= -1;
将 num
的值取反。假设 num
的初始值可能为 -1
或 1
,此操作可以在绘制完一个棋子后切换颜色,以便下一个棋子使用另一种颜色。
条件语句 (if
、else if
)
算术运算:包括整数除法和取余数操作。
函数调用 (change_piece
和 fillcircle
)
图形绘制:使用了绘图函数 setfillcolor
和 fillcircle
。
//画棋子
void draw_piece(int m,int n)
{
if (num == -1)setfillcolor(WHITE);
else if (num == 1) setfillcolor(BLACK);
int x, y;
x = m / 30;
y = n / 30;
if (change_piece(x,y) == 0)return;
fillcircle(m - (m % 30) + 15, n - (n % 30) + 15, 13);
num *= -1;
}
//初始化二维数组
void initpiece()
{
for (int i = 0; i < 15; i++)
for (int j = 0; j < 15; j++)
piece[i][j] = 0;
}
int change_piece(int x, int y)
这是一个名为 change_piece
的函数,返回类型为 int
,接受两个整数参数 x
和 y
,代表棋子在棋盘上的位置坐标。
if (piece[x][y] != 0) return 0; else piece[x][y] = num;
如果 piece[x][y]
不等于 0
,即该位置已经有棋子,函数直接返回 0
,表示不能改变该位置的棋子。
否则,将 num
赋值给 piece[x][y]
,表示在该位置放置当前的棋子。
return 1;
函数返回 1
,表示成功改变了棋子的位置。
二维数组操作:
使用 piece[x][y]
表示棋盘上位置 (x, y)
的状态,0
表示空位,1
或 -1
表示不同颜色的棋子。
条件语句 (if
、else
):
用于检查指定位置是否为空,如果不为空则返回失败。
赋值操作:
将 num
的值赋给 piece[x][y]
,即在指定位置放置当前颜色的棋子。
返回值:
返回 1
表示成功改变棋子的位置,返回 0
表示位置已经被占用,无法放置新的棋子。
//改变棋子
int change_piece(int x, int y)
{
if (piece[x][y] != 0)return 0;
else(piece[x][y] = num);
return 1;
}
check
是一个函数,返回类型为 int
,接受两个整数参数 x
和 y
。
if (x < 2 || y < 2 || x > 12 || y > 12) return 0;
首先检查 (x, y)
是否在数组 piece
的有效范围内。如果 x
或 y
小于 2,或者大于 12,则返回 0
,表示位置无效或者超出了数组的边界。
这里对于位置 (x, y)
,检查了四个方向上的连续性:
水平方向:(x-2, y)
, (x-1, y)
, (x, y)
, (x+1, y)
, (x+2, y)
垂直方向:(x, y-2)
, (x, y-1)
, (x, y)
, (x, y+1)
, (x, y+2)
对角线方向(从左上到右下):(x-2, y-2)
, (x-1, y-1)
, (x, y)
, (x+1, y+1)
, (x+2, y+2)
对角线方向(从左下到右上):(x-2, y+2)
, (x-1, y+1)
, (x, y)
, (x+1, y-1)
, (x+2, y-2)
如果在任何一个方向上发现连续的五个相同元素(包括 (x, y)
本身),则返回 1
,表示检测到了符合条件的连续性。
如果以上所有条件都不满足(即 (x, y)
位置不符合任何连续性条件),则返回 0
。
数组的访问和边界检查
多个方向上的元素比较和逻辑判断
C 语言中的条件语句和函数定义
int check(int x, int y)
{
if (x < 2 || y < 2 || x>12 || y>12)return 0;
if (piece[x][y] == piece[x - 1][y] && piece[x][y] == piece[x - 2][y] && piece[x][y] == piece[x + 1][y] && piece[x][y] == piece[x + 2][y])return 1;
if (piece[x][y] == piece[x][y - 1] && piece[x][y] == piece[x][y - 2] && piece[x][y] == piece[x][y + 1] && piece[x][y] == piece[x][y + 2])return 1;
if (piece[x][y] == piece[x - 1][y - 1] && piece[x][y] == piece[x - 2][y - 2] && piece[x][y] == piece[x + 1][y + 1] && piece[x][y] == piece[x + 2][y + 2])return 1;
if (piece[x][y] == piece[x - 1][y + 1] && piece[x][y] == piece[x - 2][y + 2] && piece[x][y] == piece[x + 1][y - 1] && piece[x][y] == piece[x + 2][y - 2])return 1;
return 0;
}
int rules()
rules
是一个函数,返回类型为 int
,没有参数。
函数通过双重循环遍历一个二维数组 piece
,数组的大小是 15x15。
内部的两个循环用于遍历数组的每个元素 (i, j)
。
if (piece[i][j] == 0) continue;
如果数组中当前位置 (i, j)
的值为 0
,则跳过当前循环,继续下一个元素的检查。这表示如果这个位置为空(或者未被占据),则不执行后续的检查。
if (check(i, j) == 1) return 1;
调用 check
函数,传递当前位置 (i, j)
的坐标作为参数。如果 check
函数返回 1
,则说明在当前位置 (i, j)
发现了符合游戏规则的连续相同元素序列。
如果发现任何一个位置满足规则,立即返回 1
,表示游戏规则被触发。
如果所有位置都被检查过且没有发现符合规则的情况,则函数返回 0
,表示游戏规则未被触发。
双重循环:用于遍历二维数组的每个元素。
条件语句:用于检查当前位置的值,并决定是否继续执行和返回。
函数调用:调用 check
函数来检查特定位置是否符合游戏规则。
返回值:函数根据检查结果返回 0
或 1
。
//游戏规则
int rules()
{
for(int i=0;i<15;i++)
for (int j = 0; j < 15; j++)
{
if (piece[i][j] == 0)continue;
if (check(i, j) == 1)return 1;
}
return 0;
}
void reset_game()
reset_game
是一个无返回值的函数,不接受任何参数。
setbkcolor(WHITE); cleardevice(); draw_line(); draw_point(); num = 1; // 重置为黑子 initpiece();
setbkcolor(WHITE);
设置背景颜色为白色。这个函数假设是用于图形界面编程中,用来设置背景的颜色。
cleardevice();
清空绘图区域。这个函数通常用于图形界面程序中,用来清除之前绘制的内容,以便重新开始绘制新的游戏状态。
draw_line();
和 draw_point();
这两个函数可能是用来绘制游戏棋盘线条和初始的游戏棋子(点)的函数。它们的具体实现不在代码段中展示,但假设是用来绘制游戏界面元素的。
num = 1; // 重置为黑子
:
将游戏中的当前下棋方重置为黑子。这个变量 num
可能是用来表示当前轮到哪一方下棋的状态变量。将其设置为 1
,表示黑子先手或者重新从黑子开始。
initpiece();
:
这个函数调用可能用来初始化游戏棋盘的状态,将棋盘上的每个位置设置为初始状态,确保游戏重新开始时所有棋子的状态都是正确的。
图形界面编程:使用 setbkcolor
和 cleardevice
函数来处理背景颜色和清空绘图区域的操作。
界面元素绘制:假设 draw_line
和 draw_point
函数用于绘制游戏棋盘线条和初始的游戏棋子。
变量操作:通过 num
变量来控制和记录当前下棋方的状态。
函数调用:调用 initpiece
函数来初始化游戏棋盘的状态
// 重置游戏状态
void reset_game()
{
setbkcolor(WHITE);
cleardevice();
draw_line();
draw_point();
num = 1; // 重置为黑子
initpiece();
}
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
int num =1;//-1表示白子,1表示黑子
HWND hwnd1= NULL;
//定义一个二维数组存放数据
int piece[15][15];
//函数声明
void draw_line();
void draw_point();
void draw_piece(int m, int n);
void initpiece();
int change_piece(int x, int y);
int check(int x, int y);
int rules();
void reset_game();
int main()
{
char one[5];
char two[5];
printf("请输入执黑棋(先手)的姓名:");
scanf("%s", one);
printf("请输入执白棋(后手)的姓名:");
scanf("%s", two);
hwnd1= initgraph(650, 450);
while (1)
{
MOUSEMSG m;
reset_game();
while (1)
{
m = GetMouseMsg();
//如果鼠标左健按下
if (m.uMsg == WM_LBUTTONDOWN) draw_piece(m.x, m.y);
if (rules() == 1)
{
if (num == 1)
{
MessageBox(hwnd1, "白棋获胜", "胜利", MB_OK);
}
else
{
MessageBox(hwnd1, "黑棋获胜", "胜利", MB_OK);
}
break;
}
}
int a = MessageBox(hwnd1, "是否要重新开始", "重新开始", MB_YESNO);
if (a != IDYES)
{
break;
}
}
closegraph();
return 0;
}
//画棋盘
void draw_line()
{
setlinecolor(RGB(rand() % 255, rand() % 255, rand() % 255));
for (int i = 15; i <= 450; i+=30)
{
line(i, 15, i, 435);
line(15, i, 435, i);
}
}
//画点
void draw_point()
{
setfillcolor(RGB(rand() % 255, rand() % 255, rand() % 255));
fillcircle(4*30-15,4*30-15,3);
fillcircle(4*30-15,12*30-15,3);
fillcircle(8*30-15,8*30-15,3);
fillcircle(12*30-15,4*30-15,3);
fillcircle(12*30-15,12*30-15,3);
}
//画棋子
void draw_piece(int m,int n)
{
if (num == -1)setfillcolor(WHITE);
else if (num == 1) setfillcolor(BLACK);
int x, y;
x = m / 30;
y = n / 30;
if (change_piece(x,y) == 0)return;
fillcircle(m - (m % 30) + 15, n - (n % 30) + 15, 13);
num *= -1;
}
//初始化二维数组
void initpiece()
{
for (int i = 0; i < 15; i++)
for (int j = 0; j < 15; j++)
piece[i][j] = 0;
}
//改变棋子
int change_piece(int x, int y)
{
if (piece[x][y] != 0)return 0;
else(piece[x][y] = num);
return 1;
}
int check(int x, int y)
{
if (x < 2 || y < 2 || x>12 || y>12)return 0;
if (piece[x][y] == piece[x - 1][y] && piece[x][y] == piece[x - 2][y] && piece[x][y] == piece[x + 1][y] && piece[x][y] == piece[x + 2][y])return 1;
if (piece[x][y] == piece[x][y - 1] && piece[x][y] == piece[x][y - 2] && piece[x][y] == piece[x][y + 1] && piece[x][y] == piece[x][y + 2])return 1;
if (piece[x][y] == piece[x - 1][y - 1] && piece[x][y] == piece[x - 2][y - 2] && piece[x][y] == piece[x + 1][y + 1] && piece[x][y] == piece[x + 2][y + 2])return 1;
if (piece[x][y] == piece[x - 1][y + 1] && piece[x][y] == piece[x - 2][y + 2] && piece[x][y] == piece[x + 1][y - 1] && piece[x][y] == piece[x + 2][y - 2])return 1;
return 0;
}
//游戏规则
int rules()
{
for(int i=0;i<15;i++)
for (int j = 0; j < 15; j++)
{
if (piece[i][j] == 0)continue;
if (check(i, j) == 1)return 1;
}
return 0;
}
// 重置游戏状态
void reset_game()
{
setbkcolor(WHITE);
cleardevice();
draw_line();
draw_point();
num = 1; // 重置为黑子
initpiece();
}