C语言实战项目-五子棋V1.0(附带全套源代码)

游戏说明

该项目适合新手拿来练习,所用的知识点不是很多,代码部分只有100多行。主要是图形化界面的应用,本游戏实现了人人对战,可以和好朋友来进行对弈。

游戏目标:

       在15×15的棋盘上,玩家轮流落子(黑子先手),尝试在水平、垂直或对角线方向上形成连续的五子,以获得胜利。

操作方法:
  1. 落子规则: 点击鼠标左键在棋盘上的交叉点处落子,黑子为先手,白子为后手。
  2. 胜利条件: 当任一玩家在任意方向上连续放置了五个自己的棋子时,即可获胜。
  3. 游戏结束: 当有玩家达成胜利条件时,游戏会弹出提示框显示胜利者,并询问是否重新开始游戏。

游戏效果展示

游戏代码部分

1.函数的声明及头文件的使用

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<easyx.h>
#include<graphics.h>
#include<windows.h>
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();

2.主函数

使用的库和函数:
  1. stdio.h: 标准输入输出库,用于输入输出操作,如 printf 和 scanf
  2. easyx.h: EasyX 图形库的头文件,提供了绘图和窗口管理的功能。
  3. graphics.h: 图形库的头文件,用于图形绘制和界面操作。
  4. windows.h: Windows API 的头文件,提供了 Windows 操作系统的函数和宏定义。
主要功能和流程:
  • 初始化操作

    • 使用 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;
}

3.画棋盘

  1. 绘图函数
    • setlinecolor(color):设置画线的颜色。RGB(rand() % 255, rand() % 255, rand() % 255) 生成一个随机的 RGB 颜色,使得每次绘制的棋盘颜色都不同。
    • line(x1, y1, x2, y2):画线函数,用于绘制棋盘的网格线。在这里,通过循环绘制多条水平和垂直线,形成棋盘的格子。
  2. 循环和计算
    • for (int i = 15; i <= 450; i+=30):循环变量 i 从 15 开始,每次增加 30,绘制棋盘的行和列。
    • 在循环中,通过调用 line(i, 15, i, 435) 和 line(15, i, 435, i) 分别绘制垂直和水平方向上的线条。
  3. 颜色处理
    • RGB(rand() % 255, rand() % 255, rand() % 255):使用 rand() 函数生成 0 到 254 之间的随机整数,作为 RGB 颜色的值。这种方法可以在每次绘制时为棋盘赋予随机的颜色,增加视觉上的多样性和趣味性。
功能总结:
  • 绘制棋盘:通过循环绘制水平和垂直线,形成一个标准的 15x15 的五子棋棋盘。
  • 随机颜色:每次绘制棋盘时,使用随机生成的颜色,使得每个棋盘的外观都不同,增加了视觉吸引力和个性化。
//画棋盘
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);
	}
}

4.画点

所用知识点和功能解释:
  1. 填充函数

    • setfillcolor(color):设置填充颜色。RGB(rand() % 255, rand() % 255, rand() % 255) 生成一个随机的 RGB 颜色,用于每个棋子的填充颜色设置。
    • fillcircle(x, y, radius):绘制实心圆函数。在这里,用于绘制五子棋棋盘上的五个棋子的位置。
  2. 具体绘制位置

    • 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);
}

5.画棋子

函数声明与参数

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,此操作可以在绘制完一个棋子后切换颜色,以便下一个棋子使用另一种颜色。

所用知识点

条件语句 (ifelse 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;
}

6.初始化二维数组

//初始化二维数组
void initpiece()
{
	for (int i = 0; i < 15; i++)
		for (int j = 0; j < 15; j++)
			piece[i][j] = 0;
}

7.改变棋子

函数定义与返回类型

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 表示不同颜色的棋子。

条件语句 (ifelse)

用于检查指定位置是否为空,如果不为空则返回失败。

赋值操作

将 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;
}

8.获胜条件

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;
}   

9.游戏规则

函数定义

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;
}

10.重置游戏状态

函数定义

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<stdio.h>
#include<easyx.h>
#include<graphics.h>
#include<windows.h>
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();
}

  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值