您现在的位置是:首页 >学无止境 >三子棋游戏的实现(C语言)网站首页学无止境
三子棋游戏的实现(C语言)
三子棋游戏的实现,在这里我们要求满足:
- 游戏不退出,继续下一把(循环)
 - 用多文件的形式实现,如下:
 
- 用game.h文件存放函数的声明并包含需要的头文件
 - 用game.c文件存放各个函数的具体实现
 - 用test.c文件实现游戏的测试,运行
 
目录
一、游戏实现流程
- 在菜单选择界面,选择开始或者退出游戏
 - 创建棋盘并初始化
 - 打印棋盘
 - 玩家下棋
 - 判断胜负
 - 电脑下棋
 - 判断胜负
 
二、功能的实现
1.创建菜单
为了让用户可以选择玩游戏还是退出游戏,我们要在test.c文件中实现创建菜单函数,代码如下:
void menu()
{
	printf("*********************************
");
	printf("***********  1、play  ***********
");
	printf("***********  0、exit  ***********
");
	printf("*********************************
");
} 
2.创建棋盘并初始化
在这里我们用二维数组来实现棋盘的创建,代码如下:
#define ROW 3
#define COL 3
char board[ROW][COL] = { 0 }; 
这里使用了宏定义,提高了可扩展性,如果以后要修改棋盘的尺寸,我们直接修改宏定义的值即可
并且一开始将它初始化为空格,代码如下:
void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
} 
3、打印棋盘
我们要打印这样的棋盘:

可以使用循环, 将棋盘的行分为三组,列分为三组,如图:

但是打印最后一行时,没有"---|---|---"分界线,打印最后一列时,没有"|",所以我们要注意条件控制。代码如下:
void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		//1、打印数据
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("
");
		//2、打印分割线
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("
");
		}
	}
} 
4、玩家下棋
在这里,玩家下棋为用字符 '*' 表示,我们通过玩家输入落子的坐标来实现下棋,那么我们就需要注意:
- 玩家输入的坐标是否合法(是否超出棋盘范围)
 - 输入坐标合法的情况下,该坐标位置是否被占用
 
如果出现以上两种情况,玩家则重新输入坐标。代码如下:
void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("玩家下棋>:
");
	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("坐标被占用,不能落子,请重新输入坐标
");
			}
		}
		//坐标非法
		else
		{
			printf("坐标非法,请重新输入
");
		}
	}
} 
如发生,运行结果如下:

在代码中我们判断坐标是否合法处用的是 if (x >= 1 && x <= row && y >= 1 && y <= col) ,x、y从1开始,因为对于玩家而言,棋盘就是从第一行第一列开始的,所以在下面判断棋盘是否被占用时,X和Y要减1(board[x - 1][y - 1])。
5、电脑下棋
我们用字符 '#' 来表示电脑所下棋子,在这里电脑下棋是要产生随机值的,所以在主函数中我们要用到 srand((unsigned int)time(NULL)); 代码如下:
void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋>:
");
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
} 
这里x = rand() % row,y = rand() % col 保证了电脑下棋产生的随机值在棋盘范围内。
6、判断输赢
在判断输赢时,我们通过设计的字符函数的返回值来判断:
- 返回 '*' 表示玩家获胜
 - 返回 '#' 表示电脑获胜
 - 返回 '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[i][2] && board[i][0] != ' ')
		{
			return board[i][0];
		}
	}
	//列
	for (i = 0; i < col; i++)
	{
		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[1][1] != ' ')
	{
		return board[1][1];
	}
	//平局
	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}
	//继续
	return 'C';
} 
在平局的时候,棋盘被下满棋子,并且未分出胜负,我们用 int IsFull(char board[ROW][COL], int row, int col) 函数来判断棋盘是否被已满,代码如下:
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;
} 
三、代码汇总
1、game.h文件
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#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); 
 
2、game.c文件
#include"game.h"
void InitBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, 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, j = 0;
	for (i = 0; i < row; i++)
	{
		//1、打印数据
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j < col - 1)
			{
				printf("|");
			}
		}
		printf("
");
		//2、打印分割线
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("
");
		}
	}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("玩家下棋>:
");
	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("坐标被占用,不能落子,请重新输入坐标
");
			}
		}
		//坐标非法
		else
		{
			printf("坐标非法,请重新输入
");
		}
	}
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋>:
");
	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;
	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;
	//行
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];
		}
	}
	//列
	for (i = 0; i < col; i++)
	{
		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[1][1] != ' ')
	{
		return board[1][1];
	}
	//平局
	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}
	//继续
	return 'C';
} 
3、test.c文件
#include"game.h"
void menu()
{
	printf("*********************************
");
	printf("***********  1、play  ***********
");
	printf("***********  0、exit  ***********
");
	printf("*********************************
");
}
void game()
{
	char board[ROW][COL] = { 0 };
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	//下棋
	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("玩家赢
");
	}
	else if (ret == '#')
	{
		printf("电脑赢
");
	}
	else
	{
		printf("平局
");
	}
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do 
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏
");
			break;
		default:
			printf("选择错误,请重新选择!
");
			break;
		}
	} while (input);
	return 0;
} 
 
四、游戏实现演示
1、玩家赢 
 
2、电脑赢

 3、平局 
 
 
这就是三子棋游戏的实现了,希望能对你有帮助呀!快来在自己电脑上实现它吧!
            




U8W/U8W-Mini使用与常见问题解决
QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结