【C语言】三子棋游戏(判断输赢修改版)

目录

0.前言

1. 游戏框架

2.game中棋盘的操作

2.1初始化棋盘

2.2 打印棋盘

3.game函数中游戏的实现

3.1 玩家下棋

3.2 电脑下棋

3.3 判断输赢

3.3.1 准备工作

3.3.2 判断输赢函数的实现

3.4 游戏展示

4.游戏代码


0.前言

目的:实现玩家和电脑简单的三子棋游戏

玩家棋子:* 

电脑棋子:#

游戏结构:

  • test.c(用于测试游戏,主程序的实现)
  • game.c(游戏函数的定义实现)
  • game.h(游戏函数的声明)

1. 游戏框架

  • 用input接收玩家的输入
  • 1为开始游戏,0为退出游戏,其余的输入放到default里面
  • 当输入为0的时候,while的条件判断也为假,退出循环,也就是退出游戏

【C语言】三子棋游戏(判断输赢修改版)_第1张图片

2.game中棋盘的操作

  1. 当玩家选择1玩游戏的时候,case 1中新建game函数,然后开始实现game函数
  2. 这里希望棋盘的大小随意控制,利用define定义常量,在game.h文件中,所以要引用game.h头文件

【C语言】三子棋游戏(判断输赢修改版)_第2张图片

 【C语言】三子棋游戏(判断输赢修改版)_第3张图片

 写在test.c中的程序:

2.1初始化棋盘

game函数中初始化棋盘

【C语言】三子棋游戏(判断输赢修改版)_第4张图片

game.h中声明初始化棋盘的函数

【C语言】三子棋游戏(判断输赢修改版)_第5张图片

  • game.c中对初始化棋盘函数进行实现
  • 因为这里用到了ROW、COL定义的标识符常量,所以也需要引用头文件game.h
  • 初始化棋盘的作用是将board里面的元素初始化掉,这样不管一开始棋盘里面方的啥,都不受影响

【C语言】三子棋游戏(判断输赢修改版)_第6张图片

2.2 打印棋盘

  • 同样再geme函数里面打印棋盘,然后.h中声明,.c中定义
  • 因为这里.c中打印也需要printf,干脆直接将stdio放到game.h中,让test.c和game.c引用game.h就行

  • 函数的声明省略了图片,下面是打印棋盘函数的实现

【C语言】三子棋游戏(判断输赢修改版)_第7张图片

  • 首先,我们希望的棋盘是这样的,颜色无所谓。

【C语言】三子棋游戏(判断输赢修改版)_第8张图片

  • 因为我们下的棋放在正中间才好看,所以打印的时候是 " %c " 两边有空格,每三个位置过后需要一个 | 分隔两个棋子。因为最后的一列通常是没有 | 分隔的,所以有个if判断。第一行打印完加个换行
  • 打印--- 分开上下棋子的时候,因为往往最后一行是没有的。所以,一开始就放到if判断中去,满足条件就打印分隔行(---)。if里面具体的实现和前面一样
  • 最后打印的棋盘如图

【C语言】三子棋游戏(判断输赢修改版)_第9张图片

3.game函数中游戏的实现

用个死循环while实现玩家和电脑的下棋操作,当出现胜负的时候在跳出循环

【C语言】三子棋游戏(判断输赢修改版)_第10张图片

3.1 玩家下棋

首先,玩家操作过,要将棋盘打印出来【C语言】三子棋游戏(判断输赢修改版)_第11张图片

【C语言】三子棋游戏(判断输赢修改版)_第12张图片

  • 用x、y保存玩家输入的位置
  • 因为正常用户不知道数组下标从0开始,所以判断的时候是>=1 && <= row
  • 如果输入坐标错误,或者输入的位置已经有棋子,就报错。通过while的循环直到玩家正确操作为止,break跳出玩家移动

3.2 电脑下棋

【C语言】三子棋游戏(判断输赢修改版)_第13张图片

  • 电脑下棋的代码比较简单,因为只需要让电脑下棋的坐标通过随机数产生就行了
  • 这里rand%row,就能是生成的随机数刚刚适合整个棋盘
  • 使用rand需要srand,而srand需要time时间戳。所以game.h文件中需要包含stdlib和time的头文件

【C语言】三子棋游戏(判断输赢修改版)_第14张图片

  •  而srand只需要设置一次,所以只需要在主函数的test函数中设置一次随机种子就行

3.3 判断输赢

3.3.1 准备工作

  • 这里用TDD的思想,先要实现什么任务,然后再怎么去实现
  • 因为每次走了一步棋子都要判断一下是否输赢,所以每次玩家或者电脑走了打印棋盘后都要判断一下游戏结果
  • 这里定义四种结果(* 玩家赢,#电脑赢,Q 平局, C 继续)
  • 所以IsWin需要返回值,且需要定义一个char变量接收返回值。如果不是C继续下棋的话,直接跳出循环
  • 最后循环结束的话,根据返回值,打印游戏的结果

【C语言】三子棋游戏(判断输赢修改版)_第15张图片

3.3.2 判断输赢函数的实现

  •  因为鹏哥的视频只是针对3*3的
  • 这样的话,棋盘就不能扩展了。那之前为什么打印棋盘之类的要用循环来写呢,之前的操作不是得不偿失嘛
  • 所以判断输赢的代码自己尝试实现,因为早都写好了,但是总有好多个bug,比如没有连成线也获胜了....

【C语言】三子棋游戏(判断输赢修改版)_第16张图片

  • 当时完成的代码是这样的
  • 因为还没有学习到关于二维数组的讲解,下面的内容可能会出错....

【C语言】三子棋游戏(判断输赢修改版)_第17张图片

  •  比如刚刚出错的,假如i=j=1的话,对应的中间那个位置。但是这样j+2的时候,二维数组就会越界。这样计算机就会把(1,1)(1,2)(2,1)的这三个连在一块,就会出现上面的错误(因为j=2的时候没法再往下加了,强行加就会得到下一行的首元素)
  • 当然,上面也只是猜测,毕竟水平有限。不过通过代码我们可以得到论证

【C语言】三子棋游戏(判断输赢修改版)_第18张图片

【C语言】三子棋游戏(判断输赢修改版)_第19张图片

  •  这样简单的论证,说明前面数组越界还是比较靠谱的
  • 所以要把代码修改一下,保证i,j加减后不会超过0到row,col的范围
  • 这里比如i+1,i+2只要保证最大值,也就是i+2不要超过row就行了
  • 如果有相减的话,保证最小值不要小于0就行

【C语言】三子棋游戏(判断输赢修改版)_第20张图片

最后将判断IsFull函数写完就ok了

【C语言】三子棋游戏(判断输赢修改版)_第21张图片

3.4 游戏展示

  • 之前的问题就不会出现了
  • Tips:如果之前的猜测是正确的,那么可以按照这种逻辑改成五子棋。而且将电脑移动换成玩家2移动的话,可以实现两人对弈

【C语言】三子棋游戏(判断输赢修改版)_第22张图片

4.游戏代码

test.c 主程序部分

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
	printf("************************************\n");
	printf("********* 1.play    0.exit *********\n");
	printf("************************************\n");
}
void game()
{
	char ret = 0;
	char board[ROW][COL] = { 0 };

	InitBoard(board, ROW, COL);	 // 初始化棋盘
	DisplayBoard(board, ROW, COL); // 打印棋盘

	while (1)
	{ 
		PlayerMove(board,ROW,COL);   //玩家下棋
		DisplayBoard(board, ROW, COL); // 打印棋盘
		ret = IsWin(board,ROW,COL); // 判断输赢
		if (ret != 'C')
		{
			break;
		}
		ComputerMove(board, ROW, COL); //电脑移动
		DisplayBoard(board, ROW, COL); // 打印棋盘
		ret = IsWin(board,ROW,COL); // 判断输赢
		if (ret != 'C')
		{
			break;
		}
	}
	// 打印游戏结果
	if (ret == '*')
		printf("玩家赢\n");
	else if (ret == '#')
		printf("电脑赢\n");
	else
		printf("平局\n");
}

void test()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	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);
}

int main()
{
	test();
	return 0;
}

game.h 函数声明部分

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 

#define ROW 3
#define COL 3

void 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);

char IsWin(char board[ROW][COL],int row,int col);

game.c 函数实现部分

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include 

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;
	for (i = 0; i < row; i++)
	{
		
		int j = 0;
		for (j = 0; j < col; j++)
		{
			// 打印一行数据
			printf(" %c ", board[i][j]);
			if(j\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("坐标不正确,请重新输入\n");
		}
	}
}

void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑走:>\n");

	while (1)
	{
		x = rand() % row;   // 生成坐标
		y = rand() % row;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}

}

// 1满了 0没有满
int IsFull(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 IsWin(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] != ' '&&board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2]&&j+2=0&&j+1=0)// 判断副对角线(包括平行)
				return board[i][j];
		}
	}
	if (1 == IsFull(board, ROW, COL))
	{
		return 'Q';
	}
	return 'C';
}

你可能感兴趣的:(【C语言小游戏】,c语言,游戏,visual,studio)