《如何使用C语言去下三子棋?》

news/2024/5/18 16:36:51 标签: c语言, 开发语言, c++, 游戏程序

目录

一、环境配置

二、功能模块

        1.打印菜单

2.初始化并打印棋盘

3、行棋 

        3.1玩家行棋

        3.2电脑行棋

4、判断是否和棋 

5.判赢

三、代码实现

        1、test.c文件

        2、game.c文件

        3、game.h文件


一、环境配置

        本游戏用到三个文件,分别是两个源文件test.c  game.c 和一个头文件game.h。

        主函数main()在test.c文件中,游戏实现所需要的函数在test.c中被引用,而函数的实现主要是在game.c文件中完成。game.h文件中包含了程序所需的所有头文件并且包括对实现游戏功能的所有函数的声明。

        之所以使用3个文件是因为,三子棋的实现需要多个模块的相互串联,多个文件各司其职,这样可以更好的处理各个模块间的逻辑,这样也增加了代码的可读性,而且还利于调试。

二、功能模块

1.打印菜单

void menu()
{
	
	printf("********************************\n");
	printf("*****        1.play        *****\n");
	printf("*****        0.exit        *****\n");
	printf("********************************\n");
}

  运行结果: 

 玩家选择(1/0)决定是否进入游戏。

 2.初始化并打印棋盘

InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
			
		}
		
	}
}
/* 通过创建一个char类型的二维数组对其进行初始化 */
char board[ ][ ] = { 0 };       
void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j;
	for (i = 0; i < row; i++)
	{
		j = 0; 
		for ( j; j < col; j++) //打印   |   |   
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		
		printf("\n");
		j = 0;
		for ( j; j < col; j++)//打印---|---|---
		{
			if (i < row - 1)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

 运行结果:

 其中,上述棋盘的大小可以根据用户需求自行调整。

 棋盘大小调整方式:在game.h文件中,对宏的定义进行更改即可完成棋盘大小的修改。

#define ROW 3
#define COL 3

3、行棋 

3.1玩家行棋

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家走:>\n");
	while (1)
	{
		printf("请输入下棋的坐标:>");
		scanf("%d %d", &x, &y);
		//判断坐标的合法性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//下棋
			//首先判断坐标是否被占用
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';//玩家使用*下棋
				
				break;
			}
			else
			{
				printf("坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入!");
		}
		
	}
}

3.2电脑行棋

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑走:>");
	while (1)
	{
		//生成随机坐标
		int x = rand() % row;
		int y = rand() % col;
		
		//下棋
		//判断坐标是否被占用
		if (board[x][y] == ' ')
		{
			printf("%d %d\n", x + 1, y + 1);//输出电脑下棋的坐标
			board[x][y] = '#';//电脑使用#下棋

			break;
		}
			
	}
}

         电脑和玩家每走一步棋,都会打印出新的棋盘,以便于玩家观察空子的位置。

4、判断是否和棋 

int IfFull(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;//棋盘没满
			}
		}
	}
	return 1;//棋盘满了
}

        在game.c文件中通过IfFull函数实现对棋盘上空位的判断,防止一个位置多次下棋。

        如果棋盘所有格子都下完之前,还没有分出胜负 ,则代表和棋,以上代码为判断棋盘上面是否有空格子。

5.判赢

char IfWin(char board[ROW][COL], int row, int col)
{
	//判断行
	for (int i = 0; i < row; i++)
	{
		for (int j = 2; j < col; j++)
		{
			if (board[i][j - 2] == board[i][j - 1] && board[i][j - 1] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断列
	for (int j = 0; j < col; j++)
	{
		for (int i = 2; i < row; i++)
		{
			if (board[i - 2][j] == board[i - 1][j] && board[i - 1][j] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断右交叉
	for (int i = 2; i < row; i++)
	{
		for (int j = 2; j < col; j++)
		{
			if (board[i - 2][j - 2] == board[i - 1][j - 1] && board[i - 1][j - 1] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断左交叉
	for (int i = 1; i < row - 1; i++)
	{
		for (int j = 1; j < col - 1; j++)
		{
			if (board[i - 1][j + 1] == board[i][j] && board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断平局
	int full = IfFull(board, row, col);
	if (full == 1)
	{
		return 'Q';
		
	}
	//游戏继续
	return 'C';
}

        每下一步棋,都会对棋盘的每行、每列、左交叉、右交叉做出判断,看是否有三个一样的旗子相连,如果有代表下棋者获胜,否则继续下棋,直至下满棋盘。

        return board[ i ][ j ] ;的奥妙之处就在于,无论是玩家获胜还是电脑获胜都会返回与其相同的棋子,不需要再重新进行判断取胜的棋子是哪一方,如果返回'*',证明玩家获胜,game()函数得到'*',判定玩家获胜,输出:“玩家获胜!”;如果返回'#',证明电脑获胜,game()函数得到'#',判定电脑获胜,输出:“电脑获胜!”

        如果通过IfFull()函数判断棋盘已经下满,就会给test.c文件中的game()函数中返回'Q’,game()函数得到'Q'便知道二者微分胜负,输出:和局。

        否则,return ’C',game()函数得到‘C’,游戏继续。

三、代码实现

1、test.c文件

#include"game.h"
char ret = 0;//ret用来存放比赛结果
void menu()
{
	
	printf("********************************\n");
	printf("*****        1.play        *****\n");
	printf("*****        0.exit        *****\n");
	printf("********************************\n");
}

void game()
{
	//存储数据 - 二维数组
	char board[ROW][COL];
	//初始化棋盘 - 初始化空格
	InitBoard(board,ROW,COL);
	//打印棋盘 - 本质是打印数组的内容
	DisplayBoard(board, ROW, COL);
	//玩家 电脑 走旗
	while (1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL); //打印玩家的每一步走棋
		//判断玩家是否赢得游戏
		ret = IfWin(board, ROW, COL);//玩家赢了*  电脑赢了#  平局Q  游戏继续C
		if (ret != 'C')
			break;
			
		//电脑下棋
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL); //打印电脑的每一步走棋
		//判断电脑是否赢得游戏
		ret = IfWin(board, ROW, COL);
		if (ret != 'C')
			break;
		
	}

	if (ret == '*')
	{
		printf("%c玩家获胜!\n", ret);

	}
	else if (ret == '#')
	{
		printf("%c电脑获胜!\n", ret);

	}
	else 
	{
		printf("%c     平局!\n", ret);
	}
	
	DisplayBoard(board, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//配合rand()函数生成随机值,因为只需要调用一次所以放到main()函数中
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("三子棋游戏\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}

	} while (input);
	return 0;
}

2、game.c文件

#include"game.h"

//初始化棋盘的函数
InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
			
		}
		
	}
}

//打印棋盘的函数
void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j;
	for (i = 0; i < row; i++)
	{
		j = 0; 
		for ( j; j < col; j++) //打印   |   |   
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		
		printf("\n");
		j = 0;
		for ( j; j < col; j++)//打印---|---|---
		{
			if (i < row - 1)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

//玩家下棋的函数
void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家走:>\n");
	while (1)
	{
		printf("请输入下棋的坐标:>");
		scanf("%d %d", &x, &y);
		//判断坐标的合法性
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//下棋
			//首先判断坐标是否被占用
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';//玩家使用*下棋
				
				break;
			}
			else
			{
				printf("坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入!");
		}
		
	}
}

//电脑下棋的函数
void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑走:>");
	while (1)
	{
		//生成随机坐标
		int x = rand() % row;
		int y = rand() % col;
		
		//下棋
		//判断坐标是否被占用
		if (board[x][y] == ' ')
		{
			printf("%d %d\n", x + 1, y + 1);//输出电脑下棋的坐标
			board[x][y] = '#';//电脑使用#下棋

			break;
		}
			
	}
}

//判断棋盘是否已经满了的函数
int IfFull(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;//棋盘没满
			}
		}
	}
	return 1;//棋盘满了
}

//判断游戏结果的函数
char IfWin(char board[ROW][COL], int row, int col)
{
	//判断行
	for (int i = 0; i < row; i++)
	{
		for (int j = 2; j < col; j++)
		{
			if (board[i][j - 2] == board[i][j - 1] && board[i][j - 1] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断列
	for (int j = 0; j < col; j++)
	{
		for (int i = 2; i < row; i++)
		{
			if (board[i - 2][j] == board[i - 1][j] && board[i - 1][j] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断右交叉
	for (int i = 2; i < row; i++)
	{
		for (int j = 2; j < col; j++)
		{
			if (board[i - 2][j - 2] == board[i - 1][j - 1] && board[i - 1][j - 1] == board[i][j] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断左交叉
	for (int i = 1; i < row - 1; i++)
	{
		for (int j = 1; j < col - 1; j++)
		{
			if (board[i - 1][j + 1] == board[i][j] && board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
			{
				return board[i][j];
			}
		}
	}
	//判断平局
	int full = IfFull(board, row, col);
	if (full == 1)
	{
		return 'Q';
		
	}
	//游戏继续
	return 'C';
}

3、game.h文件

//头文件的包含
#include<stdio.h>
#include<stdlib.h>
#include<time.h>


//符号的定义
#define ROW 3
#define COL 3

//函数的声明

//初始化棋盘函数
InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘的函数
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断游戏结果  玩家赢了*  电脑赢了#  平局Q  游戏继续C
char IfWin(char board[ROW][COL], int row, int col);
//判断棋盘是否已经下满
int IfFull(char board[ROW][COL], int row, int col);


感谢你的阅读,希望对你有所帮助~

欢迎批评指正,共同进步!


http://www.niftyadmin.cn/n/5426415.html

相关文章

ffmpeg视频处理常用命令

1.ffmpeg主要参数 -f fmt&#xff08;输入/输出&#xff09; 强制输入或输出文件格式。 格式通常是自动检测输入文件&#xff0c; 并从输出文件的文件扩展名中猜测出来&#xff0c;所以在大多数情况下这个选项是不需要的。-i url&#xff08;输入&#xff09; 输入文件的网址-…

wayland(xdg_wm_base) + egl + opengles 渲染使用纹理贴图的旋转 3D 立方体实例(十三)

文章目录 前言一、使用 stb_image 库加载纹理图片1. 获取 stb_image.h 头文件2. 使用 stb_image.h 中的相关接口加载纹理图片3. 纹理图片——cordeBouee4.jpg二、渲染使用纹理贴图的旋转 3D 立方体1. egl_wayland_texture_cube.c2. Matrix.h 和 Matrix.c3. xdg-shell-client-pr…

阿里云国际DDoS高防接入配置最佳实践

业务接入DDoS高防产品后&#xff0c;可以将攻击流量引流到DDoS高防&#xff0c;有效避免业务在遭受大流量DDoS攻击时出现服务不可用的情况&#xff0c;确保源站服务器的稳定可靠。本文九河云的接入配置和防护策略最佳实践&#xff0c;在各类场景中使用DDoS高防更好地保护您的业…

sqllab第二关通关笔记

知识点整理&#xff1a; 数值型注入判断手法 1/1 1/0 回显不同错误注入函数 extractvalue(xml_flag,xpath) xml_flag&#xff1a;文件表示符xpath&#xff1a;文件路径&#xff1b;不能识别‘~’ ‘#’ 等特殊字符&#xff1b;遇到就报错并打印xpath内容~(十六进制表示)&#…

Vite为什么比Webpack快

本文作者为 360 奇舞团前端开发工程师 一.引言 Vite和Webpack作为两个主流的前端构建工具&#xff0c;在近年来备受关注。它们的出现使得前端开发变得更加高效和便捷。然而&#xff0c;随着前端项目规模的不断增大和复杂度的提升&#xff0c;构建工具的性能优化也成为了开发者关…

小程序vue页面中怎么改变另外个vue界面中的属性

在很多情况下&#xff0c;我们都需要在一个js或者vue中的js逻辑部分&#xff0c;去修改另外个vue界面中的属性 我目前掌握的这种方法在此记录&#xff1a; 1.在需要修改的vue界面中的属性进行注释&#xff0c;并引入公共存放属性的js文件 // const result reactive({goods_id…

mysql57开启biglog并查看biglog保姆级教程

目录 详细步骤 1.修改mysql配置文件 2.重启mysql 3.操作数据库 4.查看binglog 4.1mysqlbinlog示例: 4.2mysqlbinlog将biglog写入文件示例: 4.2.1biglog中创建表示例: 4.2.2插入示例 4.2.3更新示例 详细步骤 1.修改mysql配置文件 vi /etc/my.cnf [mysqld]下增加如下…

深度学习——SAM(Segment-Anything)代码详解

目录 引言代码目录segment-anything 代码详解build_sam.pypredictor.pyautomatic_mask_generator.py 引言 从去年年初至今&#xff0c;SAM(Segment Anything )已经问世快一年了&#xff0c;SAM凭借其强大而突出的泛化性能在各项任务上取得了优异的表现&#xff0c;广大的研究者…