C 语言—三子棋游戏的简单设计

题目思想:
用 3×3 的二维数组表示棋盘
每一个棋子的格子,也就是每个元素表示三种状态:分别是
1.未落子 ‘ ’
2.玩家落子 ‘X’
3.电脑落子 ‘O’

玩家通过输入数字作为落子位置的坐标(输入的行数与输入的列数)

直接上代码解析
1.创建出棋盘

#define _CRT_SECURE_NO_WARNINGS
//利用宏定义行和列
#define MAX_ROW 3
#define MAX_COL 3
#include <stdio.h>
#include <stdlib.h>


//  将初始化行和列的 '0' 变为空格 ' '
void init(char board[MAX_ROW][MAX_COL]) {
	//行初始化,将数组 0-2输出为' '  
	for(int row = 0; row < MAX_ROW; row++) {
		//列初始化
		for (int col = 0; col < MAX_COL; col++) {
			board[row][col] = ' ';
		}
	}
}

//  打印棋盘,定义printBoard,以二维数组的方式进行循环打印
void printBoard(char board[MAX_ROW][MAX_COL]) {
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) {
			// 打印字符,使用 %c
			printf("%c", board[row][col]);
		}
		//每次打印完一行,进行换行操作,变成3×3的数组形成的棋盘
		printf("\n");
	}
}
int main() {
	//  首先创建棋盘并初始化
	//  这里不要用board[3][3],防止后面 33 搞混,可以利用宏定义
	char board[MAX_ROW][MAX_COL] = { 0 };
	//  使用 init 函数 初始化二维数组{0}应当变成空格  ' '
	//  此处也可以将 init函数定义中的双重 for 循环直接输入
	//  但将二维数组初始化为 ' ',表示了一个固定功能的逻辑,比较适合用函数定义的方法完成
	init(board);
	//  使用while循环,进行轮流落子
	while (1) {
		//1.先打印棋盘内容
		printBoard(board);
		//2.玩家落子
		//3.电脑落子
		//4.判定胜负
	}

	system("pause");
	return 0;
}

在这里插入图片描述
确实打印出来了,但是由于初始化将二维数组中的元素变为了空格 ‘ ’
,所以输出结果看不到。

2.修改棋盘,使之打印出的是 3×3 的带有方格的棋盘

void printBoard(char board[MAX_ROW][MAX_COL]) {
	for (int row = 0; row < MAX_ROW; row++) {
		//在打印每一行之前加入横线
		printf("+--+--+--+\n");
		for (int col = 0; col < MAX_COL; col++) {
			// 打印字符,使用 %c
			// 每打印一列,在打印之前加入|
			printf("| %c", board[row][col]);
		}
		//打印之后加入|,形成 3 列。
		printf("|");
		//每次打印完一行,进行换行操作,变成3×3的数组形成的纵线棋盘
		printf("\n");
	}//打印完所有行之后在加入横线,形成横线棋盘
	printf("+--+--+--+\n");
}

在这里插入图片描述
3.玩家落子

//  玩家落子
void playerMove(char board[MAX_ROW][MAX_COL]) {
	printf("轮到玩家落子!\n");
	//加入while循环,保证用户输入错误时返回重新输入
	while (1) {
		printf("请输入落子位置的坐标(row col):");
		//添加屏幕输入模块,输入行和列坐标
		int row = 0;
		int col = 0;
		scanf("%d %d", &row, &col);
		//输入完了之后,一定要验证输入的内容,防止输入例如(1020)超过棋盘坐标
		if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL) {
			printf("您输入的坐标有误,请重新输入!\n");
			continue;//重新输入,继续循环
		}
		// 当前位置不为 ' ' ,说明有子了,也需要重新输入
		if (board[row][col] != ' ') {
			printf("当前位置有子,无法落子\n");
			continue;
		} 
		//玩家落子为 X ,结束当前循环
		board[row][col] = 'X';
		break;
	}
}

在这里插入图片描述
4.电脑落子

// 电脑落子
void computerMove(char board[MAX_ROW][MAX_COL]) {
	printf("轮到电脑落子!\n");
	while (1) {
		//电脑落子时,产生随机位置,用到随机数种子,使随机数范围在棋盘坐标以内
		int row = rand() % MAX_ROW;
		int col = rand() % MAX_COL;
		if (board[row][col] != ' '){
			// 如果行列不是空格,说明有子了,就随机生成随机数
			continue;
		}
		board[row][col] = 'O';
		break;
	}
} 

在这里插入图片描述
这里使用了清屏操作,让每次输入完后进行一次清屏,具体代码在总体代码里附上

5.判定胜负

//判断和棋的函数
int isFull(char board[MAX_ROW][MAX_COL]) {
	//如果在棋盘中找不到 ' ' ,就说明棋盘满了,只要找到 ' ' 说明没满
	//约定满了返回1,没满返回0
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) {
			if (board[row][col] == ' ') {
				//没满
				return 0;
			}
		}
	}return 1;
}

// 判定胜负,由于要返回胜负,使用char定义
// 如果是玩家赢返回 X ,电脑赢返回 O,平局返回 P,胜负未分返回 ' '
char checkwinner(char board[MAX_ROW][MAX_COL]) {
	//1.检测所有行
	for (int row = 0; row < MAX_ROW; row++) {
		if (board[row][0] != ' ' &&
			board[row][0] == board[row][1]
			&& board[row][0] == board[row][2]) {
			return board[row][0];
		}
	}
	//2.检测所有列
	for (int col = 0; col < MAX_ROW; col++) {
	if (board[0][col] != ' ' &&
		board[0][col] == board[1][col]
		&& board[0][col] == board[2][col]) {
		return board[0][col];
	}
}
	//3.检测所有对角线
	if (board[0][0] != ' ' &&
		board[0][0] == board[1][1]
		&& board[0][0] == board[2][2]) {
		return board[0][0];
	}
	if (board[2][0] != ' ' &&
		board[2][0] == board[1][1]
		&& board[0][0] == board[0][2]) {
		return board[2][0];
	}
	// 判定和棋
	if (isFull(board)) {
		return 'p';
	}return ' ';

}

在这里插入图片描述
这个结果中很多人肯定看到了问题,玩家赢的同时还在显示电脑落子,怎么改?

6.注意还有一个问题:

在这里插入图片描述
如图,在主函数中先进行玩家落子,后进行电脑落子,在电脑落子之前玩家就赢了。修改程序如下:

int main() {
	//  首先创建棋盘并初始化
	//  这里不要用board[3][3],防止后面 33 搞混,可以利用宏定义
	char board[MAX_ROW][MAX_COL] = { 0 };
	//  使用 init 函数 初始化二维数组{0}应当变成空格  ' '
	//  此处也可以将 init函数定义中的双重 for 循环直接输入
	//  但将二维数组初始化为 ' ',表示了一个固定功能的逻辑,比较适合用函数定义的方法完成
	init(board);
	char winner = ' ';
	//  使用while循环,进行轮流落子
	while (1) {
		//1.先打印棋盘内容
		printBoard(board);
		//2.玩家落子
		playerMove(board);
		winner = checkwinner(board);
		if (winner != ' ') {
			//胜负已分,结束循环
			break;
		}
		//3.电脑落子
		computerMove(board);
		//4.判定胜负
		winner = checkwinner(board);
		if (winner != ' ') {
			//胜负已分,结束循环
			break; 
		}
	}
	if (winner = 'X') {
		printf("恭喜你,获胜了!\n");
	}
	else if (winner = 'O') {
		printf("很遗憾,你有点菜呀!\n");
	}
	else {
		printf("你和电脑五五开!\n");
	}
	system("pause");
	return 0;
}

全部函数

#define _CRT_SECURE_NO_WARNINGS
//利用宏定义行和列
#define MAX_ROW 3
#define MAX_COL 3
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


//  将初始化行和列的 '0' 变为空格 ' '
void init(char board[MAX_ROW][MAX_COL]) {
	//行初始化,将数组 0-2输出为' '  
	for(int row = 0; row < MAX_ROW; row++) {
		//列初始化
		for (int col = 0; col < MAX_COL; col++) {
			board[row][col] = ' ';
		}
	}
	//设置随机数种子,为电脑落子
	//只要程序启动时,设置一次即可
	srand((unsigned int)time(0));
}

//  打印棋盘,定义printBoard,以二维数组的方式进行循环打印
void printBoard(char board[MAX_ROW][MAX_COL]) {
	//每次打印之前先清屏
	system("cls");
	for (int row = 0; row < MAX_ROW; row++) {
		//在打印每一行之前加入横线
		printf("+--+--+--+\n");
		for (int col = 0; col < MAX_COL; col++) {
			// 打印字符,使用 %c
			// 每打印一列,在打印之前加入|
			printf("| %c", board[row][col]);
		}
		//打印之后加入|,形成 3 列。
		printf("|");
		//每次打印完一行,进行换行操作,变成3×3的数组形成的纵线棋盘
		printf("\n");
	}//打印完所有行之后在加入横线,形成横线棋盘
	printf("+--+--+--+\n");
}

//  玩家落子
void playerMove(char board[MAX_ROW][MAX_COL]) {
	printf("轮到玩家落子!\n");
	//加入while循环,保证用户输入错误时返回重新输入
	while (1) {
		printf("请输入落子位置的坐标(row col):");
		//添加屏幕输入模块,输入行和列坐标
		int row = 0;
		int col = 0;
		scanf("%d %d", &row, &col);
		//输入完了之后,一定要验证输入的内容,防止输入例如(1020)超过棋盘坐标
		if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL) {
			printf("您输入的坐标有误,请重新输入!\n");
			continue;//重新输入,继续循环
		}
		// 当前位置不为 ' ' ,说明有子了,也需要重新输入
		if (board[row][col] != ' ') {
			printf("当前位置有子,无法落子\n");
			continue;
		} 
		//玩家落子为 X ,结束当前循环
		board[row][col] = 'X';
		break;
	}
}

// 电脑落子
void computerMove(char board[MAX_ROW][MAX_COL]) {
	printf("轮到电脑落子!\n");
	while (1) {
		//电脑落子时,产生随机位置,用到随机数种子,使随机数范围在棋盘坐标以内
		int row = rand() % MAX_ROW;
		int col = rand() % MAX_COL;
		if (board[row][col] != ' '){
			// 如果行列不是空格,说明有子了,就随机生成随机数
			continue;
		}
		board[row][col] = 'O';
		break;
	}
}


//判断和棋的函数
int isFull(char board[MAX_ROW][MAX_COL]) {
	//如果在棋盘中找不到 ' ' ,就说明棋盘满了,只要找到 ' ' 说明没满
	//约定满了返回1,没满返回0
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) {
			if (board[row][col] == ' ') {
				//没满
				return 0;
			}
		}
	}return 1;
}

// 判定胜负,由于要返回胜负,使用char定义
// 如果是玩家赢返回 X ,电脑赢返回 O,平局返回 P,胜负未分返回 ' '
char checkwinner(char board[MAX_ROW][MAX_COL]) {
	//1.检测所有行
	for (int row = 0; row < MAX_ROW; row++) {
		if (board[row][0] != ' ' 
			&& board[row][0] == board[row][1]
			&& board[row][0] == board[row][2]) {
			return board[row][0];
		}
	}
	//2.检测所有列
	for (int col = 0; col < MAX_ROW; col++) {
	if (board[0][col] != ' ' 
		&& board[0][col] == board[1][col]
		&& board[0][col] == board[2][col]) {
		return board[0][col];
	}
}
	//3.检测所有对角线
	if (board[0][0] != ' ' &&
		board[0][0] == board[1][1]
		&& board[0][0] == board[2][2]) {
		return board[0][0];
	}
	if (board[2][0] != ' ' &&
		board[2][0] == board[1][1]
		&& board[0][0] == board[0][2]) {
		return board[2][0];
	}
	// 判定和棋
	if (isFull(board)) {
		return 'p';
	}return ' ';

}

int main() {
	//  首先创建棋盘并初始化
	//  这里不要用board[3][3],防止后面 33 搞混,可以利用宏定义
	char board[MAX_ROW][MAX_COL] = { 0 };
	//  使用 init 函数 初始化二维数组{0}应当变成空格  ' '
	//  此处也可以将 init函数定义中的双重 for 循环直接输入
	//  但将二维数组初始化为 ' ',表示了一个固定功能的逻辑,比较适合用函数定义的方法完成
	init(board);
	char winner = ' ';
	//  使用while循环,进行轮流落子
	while (1) {
		//1.先打印棋盘内容
		printBoard(board);
		//2.玩家落子
		playerMove(board);
		winner = checkwinner(board);
		if (winner != ' ') {
			//胜负已分,结束循环
			break;
		}
		//3.电脑落子
		computerMove(board);
		//4.判定胜负
		winner = checkwinner(board);
		if (winner != ' ') {
			//胜负已分,结束循环
			break; 
		}
	}
	if (winner = 'X') {
		printf("恭喜你,获胜了!\n");
	}
	else if (winner = 'O') {
		printf("很遗憾,你有点菜呀!\n");
	}
	else {
		printf("你和电脑五五开!\n");
	}
	system("pause");
	return 0;
}

结果如下
在这里插入图片描述
我们的三子棋棋盘小游戏就算结束啦!!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值