C语言实现三子棋游戏(井字棋)

       背景

        这是我们第二个实现的游戏,上难度,这次我们来看看井字棋游戏是如何使用代码实现的吧

        首先我们需要了解三子棋的运算规则,当我们"*"和“#”中任意一个元素在行,列和对角中为3个的时候,游戏胜利,我们实现三子棋的时候是玩家与电脑进行对弈,每人一步,直到游戏胜利或者平局,游戏结束。

        实现井字棋游戏

        这次我们想要实现井字棋的代码只在一个文件中完成会有点乱,我们将代码分为3个文件来编写,首先我们需要一个文件存放主函数的代码用来测试每一段代码的运行,之后我们需要一个文件来存放我们编写的函数,最后就是头文件了,我们需要一个头文件来调用我们的函数,我们暂且就设置头文件为game.h,主函数中文件为text.c,存放函数的文件为game.c。

        代码实现

        存放主函数的text.c文件

        

#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
	printf("***************************\n");
	printf("*********  1.play  ********\n");
	printf("*********  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);
		//判断输赢
		ret =Is_Win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		DisPlayBoard(board, ROW, COL);
		
		
		ComputerMove(board, ROW, COL);
		//判断输赢
		ret =Is_Win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		DisPlayBoard(board, ROW, COL);
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		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:
			{
				printf("进入游戏\n");
				game();
				break;
			}
			case 0:
			{
				printf("退出游戏\n");
				break;
			}
			default:
			{
				printf("输入错误,请重新输入。\n");
			}

			}
	} while (input);
	return 0;
}

        存放函数的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;int j;
	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 < row;j++)
				//打印分割信息
			{
				printf("---", board[i][j]);
				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("电脑下棋\n");
	while (1)
	{
		int x = 0;
		int y = 0;
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

//满,返回1
//不满返回0
//判断井字棋下棋位置是否为空
int Is_Full(char board[ROW][COL], int row, int col)
{
	int i, j;
	for ( i = 0; i < row; i++)
	{
		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;
	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];
		}
			
	}
	//列
	int j;
	for (j = 0;j < col;j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
		{
			return board[1][j];
		}
			
	}
	//对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	//没有人赢,平局
	if (Is_Full(board, row, col))
	{
		return 'Q';
	}
	return 'C';
}

        头文件game.h

        

#pragma once
#define ROW 3
#define COL 3
#include<stdio.h>
#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 PlayerMove(char board[ROW][COL], int row, int col);

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

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

        代码分析

        text.c中主函数代码分析

        我们从主函数开始,首先我们需要一个菜单来使玩家选择是否进入游戏,是的话选择1.play,否的话选择0.exit退出游戏,这一步与我们之前在猜数游戏中的步骤别无二致。

        进行一个do while循环,当我们选择1的时候进入游戏,之后开始游戏,这里我们需要在主函数所在的页面内写一个game函数用来实现我们的游戏,让我们进入game函数中。

        game.c文件中InitBoard函数解析

        我们需要创建一个棋盘,用来存放我们相应的元素,我们的棋盘由"---"和“|”组成,那么我们如何使用他们来进行棋盘的编写呢,我们使用函数的方式,我们定义函数InitBoard来实现数组中元素的初始化,之后我们对棋盘进行一个打印。这里有两种方式,一种比较笨,一种需要我们动动脑筋。

          game.c文件中DisPlayBoard函数解析

我们来看简单的一种:

        

void DisPlayBoard(char board[ROW][COL], int row, int col)
{
	int i;int j;
	for (i = 0;i < row;i++)
	{
		//打印数据
		printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
		//打印分割信息
		if (i < row - 1)
			printf("---|---|---\n");
	}
}

        这是我们第一种代码,我们设置行数,在每一行进行遍历的时候将数据导入行中每一个元素中,之后实现棋盘的打印

        改进之后的一种:

        

void DisPlayBoard(char board[ROW][COL], int row, int col)
{
	int i;int j;
	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 < row;j++)
				//打印分割信息
			{
				printf("---", board[i][j]);
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

        这个代码巧妙的使用了循环与判断语句并且对打印棋盘的方法进行了深入思考,我们将要输入的元素精确到每一个元素。

        game.c文件中PlayerMove函数解析

        有棋盘了,之后我们玩家要下棋喽,怎么个下法呢,这里我们定义函数PlayerMove,之后将数组中每个元素的下标输入进棋盘中,我们就可以开始下棋了。

        在下棋的时候有些问题需要我们注意的,我们通过输入坐标的方式来获得我们下棋的位置,这样我们就必须对我们输入坐标的范围进行限制,如果输入正确才可以将元素放入棋盘,如果输入错误的话就输出“坐标输入错误,请重新输入”。当然这里我们还需要判断我们棋盘中元素是否为空,只有为空的时候我们才可以下棋,如果我们想下的坐标被占用,那么我们只能在棋盘中其他地方下棋喽。

        game.c文件中ComputerMove函数解析

        玩家下完棋就到电脑下棋喽,电脑是怎么下棋的呢,这里我们需要生成一个随机坐标,我们电脑就在这个随机坐标中下棋,如果在下棋的过程中坐标与我们已经下过棋的位置冲突,那么电脑就会在其他的地方下棋。我们使用srand函数来设置随机数生成的起点,我们设置起点为时间,只有时间是不断改变的,所以我们设置时间为起点的时候每次生成的随机数一定是不一样的。

         game.c文件中Is_Win函数解析

        游戏当然是要有个输赢的,所以我们这里使用函数is_win来判断谁获得了游戏的胜利,我们使用几个for循环与if语句判断行,列,和对角线上是否都一样,判断一行,一列,或者一个对角线都为*则玩家赢,为“#”则是电脑赢。

        game.c文件中Is_Full函数解析

        好啦,那在下棋的过程中,我们还要判断下的棋是否为平局,这个时候我们就需要定义一个Is_Full函数来进行运算,如果棋盘中已经被元素填满而且没有分出胜负的话,就判断为平局,那么我们让Is_Full函数返回值为1的时候表示棋盘已经满了,返回值为0的时候表示棋盘没有满。

        game.h头文件解析

        接下来我们看看头文件,在头文件中我们将所有函数名都放进去,这样我们在主函数中直接调用头文件game.h就好,我们甚至可以将头文件include<stdio.h>也放进去,那么我们在主函数中只需要定义头文件game.h,include"game.h"注意,我们这里调用自己写的头文件的时候需要使用“”而不是<>。

        运行结果

        玩家赢

        

        电脑赢

        

        平局

        

          

        今天就到这里喽,大家继续加油,对井字棋游戏有任何疑问都可以评论区留言哦,会为大家解答。嘿嘿,有不足之处也请你们指正嘞。

  • 51
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值