首页 > 其他分享 >C语言经典小游戏之三子棋

C语言经典小游戏之三子棋

时间:2024-07-28 14:54:04浏览次数:15  
标签:col int 三子 C语言 小游戏 board printf COL ROW

目录

一、代码思路

二、代码实现

1.菜单

2.实现棋盘

3.玩家下棋

 4.电脑下棋

5.判断输赢

三、代码

1.game.h代码

3.game.c代码

3.test.c代码

 


一、代码思路

首先需要创建三个文件:

test.c       //用于测试游戏的逻辑性

game.c    //游戏代码的实现

game.h   //游戏代码的声明(函数声明、符号定义)

  • 实现三子棋流程:

开始菜单--->实现棋盘--->玩家、电脑下棋--->判断输赢 

  • 主要运用了函数和数组。

二、代码实现

1.菜单

  • 首先我们需要打印一个菜单(开始游戏、结束游戏)以及最简单化游戏思路。

 由于菜单至少需要执行一次,所以这里选用do while 循环,因为要进行选择是否开始游戏,所以我们这里需要用scanf输入一个数,并且用到switch来进行游戏选择,(这里的while判断为假的时候我们需要退出循环,结束游戏,所以这里可以巧妙的选用0来实现)。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
menu()
{
	printf("**************\n");
	printf("*** 1.play ***\n");
	printf("*** 0.exit ***\n");
	printf("**************\n");
}
int main()
{
	int input = 0;
	do 
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("三子棋\n");
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
		}
		


	} while (input);
	return 0;
}
  • 注意:每写完一个版块都要测试一下,以免写完后出问题,不知道问题在哪。 

测试:

 

2.实现棋盘

首先,我们需要知道三子棋是一个3*3的格子组合而成,可以用我们的二维数组来进行实现 

  • 创建数组,初始化棋盘。(这里的ROW、COL在game.h文件中统一定义为3,这样方便于以后写多子棋,不用一个个去更改参数,game.c和test.c只需要引用头文件game.h即可)
//game.c中
void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
	}
}
//test.c中
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include"game.h"
menu()
{
	printf("**************\n");
	printf("*** 1.play ***\n");
	printf("*** 0.exit ***\n");
	printf("**************\n");
}
game()
{
	
	char board[ROW][COL] = { 0 };
	//初始化棋盘的函数
	InitBoard(board, ROW, COL);
}
int main()
{
	int input = 0;
	do 
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
		}
		


	} while (input);
	return 0;
}
//game.h中
#pragma once
#define ROW 3
#define COL 3
//初始化棋盘的函数
void InitBoard(char board[ROW][COL], int row, int col);
  •  打印棋盘,棋盘周围都有线相隔,所以我们需要用一些分割线来让数组看起来像棋盘。

这里函数的定义(test.c)声明(game.h)与上面相同,只是名称换了。 

//game.c
//打印棋盘
void DisplayBoard(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++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}


//添加到game.h
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);

//添加到test.c
DisplayBoard(board,ROW,COL);

打印结果 :这样就有一个棋盘的雏形。

 

3.玩家下棋

这里的玩家落子,我们用 来表示, 玩家输入坐标后,我们首先需要判断坐标是否合法,合法后再判断玩家下的位置是否被占用。(这里函数的定义(test.c)声明(game.h)与上面相同,只是名称换了)。

  • 这里用board[x-1][y-1]是因为,玩家在落子的时候应该只会从1开始,而数组的坐标是从0开始的,所以这里需要-1.
  • 落子完成后,我们需要打印棋盘,给玩家可读性。
//game.c中
//玩家下棋
void Player(char board[ROW][COL], int row, int col)
{
	int x = 0;//横坐标
	int y = 0;//纵坐标
	while (1)
	{
		printf("玩家下棋\n");
		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("坐标非法,请重新输入\n");
		}

	}
	
}


//添加到test.c
//玩家下棋
	Player(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);

打印结果:成功落子

 

 4.电脑下棋

要让电脑随机下棋,这里我们需要用的rand( )函数、srand( )函数和time(NULL)来生成随机数.

注意头文件的添加,要添加两个头文件在game.h中:#include<stdio.h>、#include<time.h>。

(这里函数的定义(test.c)声明(game.h)与上面相同,只是名称换了)

rand()函数和srand()函数是C语言中用于生成随机数的两个重要函数。‌

  • rand()函数:‌用于生成伪随机数。‌它存在于头文件<stdlib.h>中,‌返回一个介于0和RAND_MAX(‌通常是32767)‌之间的伪随机整数。‌这个函数使用线性同余法来计算随机数,‌这意味着在一定范围内生成一串数字,‌有一个最大周期M。‌默认情况下,‌rand()函数的种子是1,‌所以每次运行程序时生成的随机数序列都是相同的。‌为了增加随机性,‌通常会配合srand()函数使用。‌

  • srand()函数:‌用于设置随机数种子。‌它的作用是产生一个随机种子,‌将这个种子传递给rand()函数,‌从而达到生成不同的随机数序列的目的。‌srand()函数可以接受不同的参数来产生不同的种子,‌例如使用time(NULL)getpid(NULL)的返回值作为参数,‌以确保每次产生不同的种子。‌使用time(NULL)可以确保每次程序运行时产生不同的时间,‌而getpid(NULL)则用来取得目前进程的进程识别码,‌用于建立临时文件以避免文件同名问题。‌

通过结合使用rand()和srand()函数,‌可以在C语言中生成所需的随机数,‌这对于模拟、‌游戏、‌加密等多种应用场景都非常有用。‌例如,‌可以通过调用srand(time(NULL))来初始化随机数生成器,‌然后使用rand()来生成一系列的随机数,‌从而实现各种随机过程

//电脑下棋
void Computer(char board[ROW][COL], int row, int col)
{
    printf("电脑下棋\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % row;//0-2
		y = rand() % col;//0-2
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
	
	
}

不要忘了在主函数中添加srand来设置随机数起点: 

 

打印结果:

5.判断输赢

  • 到这里就快成功了,首先需要把玩家下棋和电脑下棋使用循环,让他们打回合,不然一把就结束了。
  • 然后进行输赢判断首先我们约定:玩家赢 函数返回‘*’,电脑赢 函数返回‘#’,平局 函数返回‘q’,继续 函数返回‘c’。(玩家和电脑之所以这样设定是因为,如果哪一方赢了,直接返回其中的一个棋子即可判断)
  • 三子棋里赢的条件无非是横着三个,竖着三个,对角线三个。
  • 我们还需要考虑棋盘是否放满了,如果放满了也没有人赢,那么就是平局。
  • 我们应该把这个函数放在玩家落子和电脑落子之后(两个后面都放),这样我们才能及时判断。 
//判断输赢
char Is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	//行
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}

	//列
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}
	}

	//对角
	if (board[1][1] == board[0][0] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	else if (board[1][1] == board[0][2] && board[2][0] == board[1][1] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	//平局
	if (Is_full(board, row, col))
	{
		return 'q';
	}
	return 'c';
}
//判断是否满盘
//满了返回1,没满返回0
int Is_full(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}

基本流程到这里就结束了。

三、代码

1.game.h代码

#pragma once
#define ROW 3
#define COL 3

#include<stdlib.h>
#include<time.h>
//初始化棋盘的函数
void InitBoard(char board[ROW][COL], int row, int col);

//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);

//玩家下棋
void Player(char board[ROW][COL], int row, int col);

//电脑下棋
void Computer(char board[ROW][COL], int row, int col);

//判断输赢
char Is_win(char board[ROW][COL], int row, int col);
int Is_full(char board[ROW][COL], int row, int col);

3.game.c代码

#define _CRT_SECURE_NO_WARNINGS
#include"game.h"

//初始化棋盘
void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
	}
}

//打印棋盘
void DisplayBoard(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++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

//玩家下棋
void Player(char board[ROW][COL], int row, int col)
{
	int x = 0;//横坐标
	int y = 0;//纵坐标
	while (1)
	{
		printf("玩家下棋\n");
		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("坐标非法,请重新输入\n");
		}

	}
	
}


//电脑下棋
void Computer(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % row;//0-2
		y = rand() % col;//0-2
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

//判断是否满盘
//满了返回1,没满返回0
int Is_full(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}

//判断输赢
char Is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	//行
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}

	//列
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}
	}

	//对角
	if (board[1][1] == board[0][0] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	else if (board[1][1] == board[0][2] && board[2][0] == board[1][1] && board[1][1] != ' ')
	{
		return board[1][1];
	}

	//平局
	if (Is_full(board, row, col))
	{
		return 'q';
	}
	return 'c';
}

3.test.c代码

 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include"game.h"
menu()
{
	printf("**************\n");
	printf("*** 1.play ***\n");
	printf("*** 0.exit ***\n");
	printf("**************\n");
}
game()
{
	char r = 0;//接收输赢的返回值
	char board[ROW][COL] = { 0 };
	//初始化棋盘的函数
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);

	while (1)
	{
		//玩家下棋
		Player(board, ROW, COL);
		//判断输赢
		r = Is_win(board, ROW, COL);
		if (r != 'c')
			break;
		//打印棋盘
		DisplayBoard(board, ROW, COL);
		

		//电脑下棋
		Computer(board, ROW, COL);
		//判断输赢
		r = Is_win(board, ROW, COL);
		if (r != 'c')
			break;
		//打印棋盘
		DisplayBoard(board, ROW, COL);
	}
	if (r == '*')
	{
		printf("玩家赢\n");
	}
	else if (r == '#')
	{
		printf("电脑赢\n");
	}
	else if (r == 'q')
	{
		printf("平局\n");
	}
	//打印棋盘
	DisplayBoard(board, ROW, COL);
}
int main()
{
	srand((unsigned int)time(NULL));//设置随机数起点
	int input = 0;
	do 
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
		}
		


	} while (input);
	return 0;
}

最终代码运行效果:

 


当然这个代码可能存在bug,还有很多可优化性,可以自己尝试更改代码 ,如果哪里写错了,欢迎指正。

标签:col,int,三子,C语言,小游戏,board,printf,COL,ROW
From: https://blog.csdn.net/2203_75522143/article/details/140664369

相关文章

  • C语言笔记
    各位同好,作为一名C语言学习小白,在经过了一个学期的学习后我拿到了满分的期末成绩,现分享给大家自认为宝贵的笔记。开始写一些C语言的笔记取位数个位:n%10十位:n/10%10百位:n/100%10冒泡排序for(i=1;i<=n-1;i++)     for(j=0;j<n-i;j++)     ......
  • 【C语言】文件操作,文件读写详细介绍
    目录为什么要使用文件?文件概念1.什么是文件?2.程序文件3.数据文件4.文件名文件的使用1.文件指针2.文件的打开与关闭文件的顺序读写 1.顺序读写函数2.scanf系列与printf系列文件的随机读写 1.fseek2.ftell3.rewind文本文件,二进制文件 文件读取结......
  • c语言-指针
    6指针一、指针是什么1、指针是地址(1)地址是什么?a. 内存中用于cpu标识的一组编号   --是以十六进制的形式存储的b.cpu要么是32位,要么是64位的地址针注:这里电脑是64位,而空间是16G,这是因为电脑还有内存条,一个内存条有8G,所以总共是16G。这里的RAM是动态内存,是正在使用......
  • c语言模拟Python的命名参数
    最近在书里看到的,让c语言去模拟其他语言里有的命名函数参数。觉得比较有意思所以记录一下。目标众所周知c语言里是没有命名函数参数这种东西的,形式参数虽然有自己的名字,但传递的时候并不能通过这个名字来指定参数的值。而支持命名参数的语言,比如python里,我们能让代码达到这种效......
  • C语言内存函数精讲
    目录引言1.内存分配函数malloc2.内存释放函数free3.内存拷贝函数memcpy4.内存移动函数memmove5.内存设置函数memset6.内存比较函数memcmp总结 引言在C语言编程中,内存管理是核心技能之一。C语言提供了一系列内存操作函数,这些函数在动态内存分配、数据拷贝和比较等方......
  • 【C语言】结构体
    目录一、结构体概念二、定义结构体类型三、定义和引用结构体类型变量3.1 先定义结构体类型再定义变量名3.2 在定义类型的同时定义变量3.3直接定义结构类型变量3.4类型与变量区别   3.5结构体的嵌套定义   3.6结构体类型变量的引用3.7 结构体类型......
  • C语言——字符串拼接strcat及自实现代码
    strcat函数在C语言中,strcat函数用于将两个字符串连接起来,即将源字符串(sourcestring)追加到目标字符串(destinationstring)的末尾,并返回目标字符串。这个函数定义在头文件<string.h>中。函数原型如下:char*strcat(char*dest,constchar*src);dest:目标字符串的指针,这个字符......
  • 数据结构——链式二叉树(C语言版)
    链式二叉树的结构⽤链表来表⽰⼀棵⼆叉树,即⽤链来指⽰元素的逻辑关系。通常的⽅法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别⽤来给出该结点左孩⼦和右孩⼦所在的链结点的存储地址。                                ......
  • 学习c语言第十五天(初阶测评)
    选择题1.下列程序输出结果为672.下列程序输出结果为 死循环打印3.i和j的值分别为什么 214.k的终值是什么905.输出结果是什么 16.正确的是    C7.C语言规定main函数位置    C8.不正确的是    D9.正确的是     c ......
  • C语言初阶(6)
    1.函数递归定义程序调用自身的编程技巧称为递归。递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可......