C语言实现简单三字棋(井字棋Tic Tac Toe)游戏

目录

三字棋介绍

C语言实现三字棋的预期功能

游戏规则

三字棋的基本规则

游戏设计及代码实现

 游戏开始界面

 玩家输入输出

 棋盘

初始化棋盘

打印棋盘

玩家下棋

电脑下棋

判断输赢 

棋盘占满 

完整的源代码及注释

头文件 game.h 的文件代码:

源文件 test.c 的文件的代码:

 源文件 game.c 的文件代码:


三字棋介绍

三字棋,也被称为井字棋(Tic Tac Toe),是一种非常简单的两人对战策略游戏。在这个游戏中,两位玩家分别代表X和O,在3x3的棋盘上轮流落子。游戏的目标是在棋盘的任何一行、一列或对角线上首先连成三个相同的符号(X或O),以赢得比赛。

C语言实现三字棋的预期功能

  1. 初始化棋盘:游戏开始时,应创建一个3x3的棋盘,并用空格表示每个位置尚未落子。

  2. 玩家轮流下棋:两位玩家分别使用X和O符号轮流在棋盘上放置棋子。程序应确保每位玩家只能在下一步中选择一个空位置落子。本文程序玩家符号为  ‘*’ , 电脑符号为 ‘#’。

  3. 显示棋盘状态:在每一步之后,程序应更新并显示当前的棋盘状态,以便玩家了解游戏进展。

  4. 检查胜负条件:程序需要实现一个函数来检查当前棋盘状态,看是否有玩家已经连成三个相同的符号。如果有,则宣布该玩家获胜,并结束游戏。

  5. 处理平局情况:如果棋盘填满且没有玩家获胜,则判定为平局,程序应宣布游戏结束。

  6. 用户交互:程序应能够接收用户的输入,如选择下棋的位置,并在适当的时候给出提示或错误信息。

  7. 重新开始或退出游戏:游戏结束后,程序应提供选项供用户选择重新开始新的一局或退出游戏。

游戏规则

三字棋的基本规则

  1. 棋盘与棋子:游戏在一个3x3的棋盘上进行,每位玩家拥有一种棋子,通常分别用X和O表示。
  2. 开局与走棋:游戏开始时,两位玩家通过猜拳或其他方式决定谁先下第一步。之后,两位玩家轮流在棋盘的空格上放置自己的棋子,每次只能走一步。本文程序设定为玩家先下第一步
  3. 胜利条件:任何一位玩家先将自己的三个棋子连成一条直线(横线、竖线或对角线)时,即宣告胜利。游戏结束。
  4. 平局情况:如果棋盘上的所有空格都被填满,且没有玩家连成三个棋子,则游戏以平局结束。

游戏设计及代码实现

 游戏开始界面

游戏开始界面这里,我们使用 printf("") 打印出一个简单的游戏开始界面

代码实现

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

 玩家输入输出

 打印出游戏开始界面后,玩家需要可以选择开始游戏或者退出游戏,我们这里使用 switch case 语句,玩家输入 ’1‘  开始游戏,输入 ’0‘ 退出游戏;输入其它数字则选择错误,让玩家重新选择。游戏结束后,当我们想再进行下一次游戏时,总不能关闭程序去重新打开它。所以这里使用了 do-while 语句,当我们想继续游戏的时候,输入 ‘1’ 即可,非零为真,循环继续;退出游戏时,输入 ‘0’ 就可以,0 为假,循环终止。 

代码实现 

    //存放玩家输入的数字,‘1’开始游戏,‘0’退出游戏
	int input = 0;

	do
	{
		menu();
		printf("请选择:》");
		scanf("%d", &input);

		//‘1’开始游戏;‘0’退出游戏;其它数字,重新输入
		switch (input)
		{
		case 1:
			game();
			printf("请输入:》\n");
			break;
		case 0:
			printf("退出游戏。\n");
			break;

		default:
			printf("选择错误,请重新选择!\n");
			break;
		}

	} while (input);//选择‘0’时,退出循环,结束游戏

 棋盘

初始化棋盘

游戏开始时,程序应该创建一个3x3的棋盘,并用空格表示每个位置尚未落子。这里我们创建一个二维数组 board [ROW] [COL] (ROW为行数,COL为列数,头文件里可改变数量,本文为3);利用两个 for 循环将 board [ROW] [COL] = ’   ‘ 即可。

代码实现

//初始化棋盘,每个坐标位置应为空,还未被下棋
void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
	}
}

打印棋盘

这时候如果我们直接使用 for 循环将board [ROW] [COL] 棋盘打印出来的时候,我们是什么都看不到的,如图

 所以为了看到棋盘的样子,我们可以给棋盘加上一框,效果如图

这里用到了 ‘|’ ‘---’ 这两个符号,再用 printf 打印出来的,不过得需要循环来控制它,棋盘上棋子的位置目前为空格,观察上图,当我们在棋盘上每行打印出一个空格的时候,后面有一个 ‘|’ ,每行的最后一个没有;利用 for 循环,每打印一个 ’  ‘ 的时候,后面再打印一个 ’ | ‘,再用 if 语句设定条件,最后一个不打印。每行打印完成后,下面有一行 ’---|---|---‘,同上每打印一个 ’---‘ 的时候,后面再打印一个 ’ | ‘,再用 if 设定条件,最后一个不打印;这种有两行,同样我们可以使用 if 语句设定条件,最后一行不打印。

 代码实现

//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]);
//		}
//		printf("\n");
//	}
//}

//打印棋盘
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 < col - 1)
			{
				printf("|");
			}
			
		}
		printf("\n");
		//棋盘上的‘---|’
		if (i < row - 1)
		{
			int j = 0;
			for (j = 0; j < col; j++)

			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

玩家下棋

棋盘上落子的位置被我们初始化成了 ‘  ’ 空格,而玩家下棋就是把 ‘  ’ 空格替换成代表玩家的棋子符号 ‘ * ’即可。 

定义 x 、y 存放玩家输入的坐标,就是玩家下棋的位置;使用while语句,因为玩家需要可以多次下棋;if 条件语句,因为x 和 y 不能超过棋盘行数和列数,不然程序在棋盘上就找不到这个位置;数组的下标是从 0 开始的,但是从生活中看,序号大多从 1 开始,所以当玩家输入完坐标后,把它减去 1 就是对应棋盘上的坐标。当程序读入符合规定的 x、y 值后,if 条件语句,因为需要检查棋盘此处位置是否已经存在棋子,是否为空,不为空此处位置便不可以被下棋。

代码实现

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

	int x = 0;
	int y = 0;
	
	printf("玩家下棋(请输入要下棋的棋子坐标,中间使用空格):");
	scanf("%d %d", &x, &y);

	while (1)
	{
		//玩家输入的坐标要在 1 到行数(列数)之间
		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");
		}
	}
}

电脑下棋

和玩家下棋一样,将棋盘上 ’  ‘ 空格的位置替换成电脑的符号 ’ # ‘ 即可。

电脑棋手的坐标,可以使用随机函数 srand 随机产生,这样每次的游戏对局才能不一样。

代码实现

//电脑下棋
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() % col;

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

判断输赢 

三字棋输赢的判定是三个棋子连成一条直线(横线、竖线或对角线),所以当玩家赢的时候,有三个 ’ * ‘ 符号连成一条直线,我们只需要在棋盘上检查出现这个情况后就可以判断输赢,当函数返回 ’ * ’ 玩家赢,‘ # ’ 电脑赢。棋盘被占满,平局的时候返回 ‘ q ’。当以上所有情况都没有的时,这时是继续游戏,函数返回值设为 ‘ c '。

代码实现

//判断胜负,
//返回字符‘*’玩家赢
//返回字符‘#’电脑赢
//返回字符‘q’棋盘被占满,平局
//返回字符‘c’游戏继续
char IsWin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		//判断每行每列上的棋子是否一致,且不为空

        //每一行
		if (board[i][0] == board[i][1] && board[i][1] == board[1][2] && board[i][0] != ' ')
		{
			return  board[i][0];
		}
         //每一列
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return  board[0][i];
		}
	}

	//判断两条对角线上的棋子是否一致,且不为空

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

	//棋盘被占满,返回字符‘q'
	if (IsFull(board,row,col)==1)
	{
		return 'q';
	}
	return 'c';
}

棋盘占满 

当棋盘上的所有位置都有棋子没有空格的时候,棋盘上每一个位置都占满棋子,棋盘被占满。利用for 循环将二维数组的每一个元素和空格符号 ‘  ’ 比较,出现空格,棋盘上还有空格,可以接着下棋;没有空格,返回 1 ,判定程序便返回 ’ q ',本次游戏平局。

代码实现

//检查棋盘是否被棋子占满
int IsFull(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;
}

完整的源代码及注释

 整合全部代码,一个头文件(game.h),两个源文件(test.c)(game.c)。

头文件 game.h 的文件代码:

//头文件提供函数和类的声明//

#pragma once
#include<stdio.h>

//srand()随机函数的头文件
#include<stdlib.h>

//time()函数的头文件
#include<time.h>

//定义棋盘ROW行数、COL列数
#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);

源文件 test.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 board[ROW][COL] = { 0 };

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

	//打印出三字棋棋盘
	DisplayBoard(board, ROW, COL);

	//存放判断输赢函数 IsWin 的返回值
	char ret = 0;

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

}


int main() {

	//存放玩家输入的数字,‘1’开始游戏,‘0’退出游戏
	int input = 0;

	//srand随机函数,生成随机数
	srand((unsigned int)time(NULL));

	do
	{
		menu();
		printf("请选择:》");
		scanf("%d", &input);

		//‘1’开始游戏;‘0’退出游戏;其它数字,重新输入
		switch (input)
		{
		case 1:
			game();
			printf("请输入:》\n");
			break;
		case 0:
			printf("退出游戏。\n");
			break;

		default:
			printf("选择错误,请重新选择!\n");
			break;
		}

	} while (input);//选择‘0’时,退出循环,结束游戏

	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;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		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 < col - 1)
			{
				printf("|");
			}
			
		}
		printf("\n");
		//棋盘上的‘---|’
		if (i < row - 1)
		{
			int j = 0;
			for (j = 0; j < col; j++)

			{
				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("玩家下棋(请输入要下棋的棋子坐标,中间使用空格):");
	scanf("%d %d", &x, &y);

	while (1)
	{
		//玩家输入的坐标要在 1 到行数(列数)之间
		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() % col;

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


//检查棋盘是否被棋子占满
int IsFull(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;
}

//判断胜负,
//返回字符‘*’玩家赢
//返回字符‘#’电脑赢
//返回字符‘q’棋盘被占满,平局
//返回字符‘c’游戏继续
char IsWin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		//判断每行每列上的棋子是否一致,且不为空
		if (board[i][0] == board[i][1] && board[i][1] == board[1][2] && board[i][0] != ' ')
		{
			return  board[i][0];
		}
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return  board[0][i];
		}
	}

	//判断两条对角线上的棋子是否一致,且不为空
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
	{
		return  board[0][0];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
	{
		return  board[0][2];
	}

	//棋盘被占满,返回字符‘q'
	if (IsFull(board,row,col)==1)
	{
		return 'q';
	}
	return 'c';

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值