三子棋小游戏-c语言实现

今天我们来写一个三子棋的小游戏。

我们用工程一点的写法来写。

首先,我们创建一个新的工程,并且创建两个.c文件和一个.h文件,.h文件用来声明函数,其中一个.c用来实现函数,另一个用来进行测试

 我们在test函数中进行测试,为了避免主函数里内容过多,我们把函数测试都写入到test函数里,主函数里只留一个test函数。

 接下来,我们来实现test函数,我们首先在test函数里实现菜单功能,可以显示游戏界面,菜单函数非常简单,用printf就行。

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

我们可以考虑美观,可以加一点别的符号进行装饰,这里大家自行添加喜欢的符号即可。

接下来,我们进行选择,创建一个变量,用来接收输入,并且使用switch语句进行选择,为了使用户玩了之后可以再玩,我们使用do—while语句对逻辑进行包装,让用户自行选择。

void test() {
	int input;
	do {
		menu();
		printf("请选择:\n");
		scanf("%d", &input);
		switch (input) {
		case 1:
			printf("这里是game函数\n");
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
		}
	} while (input != 0);
}

写完后不要着急,我们要写一步,测一步,不然后边一测试,发现有几十个错误,心态一下就崩了。

 可以看到,我们写的逻辑没有问题,那么接下来,我们来实现game函数。

首先,我们要创建一个3行3列的char数组,这就是我们的棋盘,为了之后一劳永逸,想让三子棋变为四子棋,五子棋甚至十子棋,我们在.h文件中使用#define定义行和列,而且我们会发现,我们之后会在game.c里使用scanf还有printf函数,我们这里就可以直接把头文件也放到.h文件中。

#include <stdio.h>
#define ROW 3
#define COL 3

像这样,之后我们只需在game.c和test.c里引入.h文件即可(使用#include "game.h"),接着,我们来对棋盘进行初始化,将board数组里全部元素都初始化为空格,初始化函数我们写在game.c里,在game.h文件中进行声明

void init_board(char board[ROW][COL], int row, int col) {
	int i;
	for (i = 0; i < row; i++) {
		int j = 0;
		for (j = 0; j < col; j++) {
			board[i][j] = ' ';
		}
	}
}

注意,赋值字符给char数组时,要使用单引号,而不是双引号。

初始化完成后,我们来实现打印棋盘的函数,之后的函数都是在game.h中进行声明,game.c里实现,我之后就不啰嗦啦,为了美观和便于识别,我们给棋盘加一些边界线,我们来看一下打印出来的效果

 可以看到,我们打印出来一个类似#的图案,中间的空位,就是我们用来下棋的。

那这个棋盘我们该怎么打印呢?我们仔细观察发现,整个棋盘可以被分为三块,第一行和第一行下面的下划线,第二行和第二行下面的下划线,第三行(我们可以先给第三行打印下划线,之后去掉即可),而每一行又可以分成三部分,三个元素(空格、棋子、空格或者三个下划线)加一个竖线,同样的思路,我们可以把三个元素和一个竖线分为一组,我们这样来写

void print_board(char board[ROW][COL], int row, int col) {
	int i;
	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 < col - 1) {
			for (j = 0; j < col; j++) {
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

这里给大家展示一下我们使用#define定义行和列的好处,如果我们改变ROW和COL为10,可以得到这样的结果:

是不是很方便呢?我们接着完成我们的三子棋,打印完棋盘后,我们该写玩家下棋和电脑下棋的函数了。

void player_move(char board[ROW][COL], int row, int col) {
	printf("玩家下棋,请选择坐标:\n");
	int x, y;
	do {
		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");
		}
	} while (1);
}

因为玩家是不知道数组是从0开始的,玩家认为的是第一行和第一列而不是第0行和第0列,所以我们要在x,y的基础上减去一,我们还要判断玩家输入坐标的合法性,不能超过棋盘,也不能在已经下过棋的位置继续下棋。

void computer_move(char board[ROW][COL], int row, int col) {
	printf("电脑下棋:\n");
	while (1) {
		int x = rand() % ROW;
		int y = rand() % COL;
		if (board[x][y] == ' ') {
			board[x][y] = '#';
			break;
		}
	}
}

电脑下棋就不需要考虑这么多了,直接下就完事,不过要记住,在调用rand函数前要先调用srand函数,这个函数详细可以参考我之前的猜数字游戏,里边我进行了详细的介绍

(4条消息) 猜数游戏(详细讲解)_KLZUQ的博客-CSDN博客_猜数游戏

我们再来测试一下我们的代码

非常好,我们接着往下写

我们要让玩家和电脑不断的下棋,直到分出胜负或者棋盘填满为止,所以我们使用while将我们test函数里的代码包起来,之后,我们要就行胜负判断,每次判断后有四种结果,玩家胜,电脑胜,平局或者游戏继续。

 

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][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[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) == 1) {
		return 'Q';
	}
	return 'C';
}

我们规定,返回 ' * ' 为玩家获胜,返回 ' # ' 为电脑获胜,返回Q为平局,返回C为继续游戏,所以我们根据判断结果直接返回数组中的元素即可,Q和C单独讨论,因为Q是平局,所以我们需要一个新的函数来判断棋盘是否满了,这个函数不需要在game.h中进行声明,因为这只是一个用在game.c里用来辅助的函数。

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;
}

如果数组内有空格,说明棋盘未满,返回0,否则返回1。

此时我们在game函数里创建新的char变量用来接收胜负判断的返回值,再根据返回结果进行包装。

void game() {
	char board[ROW][COL];
	init_board(board, ROW, COL);
	print_board(board, ROW, COL);
	char ret;
	while (1) {
		player_move(board, ROW, COL);
		print_board(board, ROW, COL);
		ret=is_win(board, ROW, COL);
		if (ret != 'C') {
			break;
		}
		computer_move(board, ROW, COL);
		print_board(board, ROW, COL);
		ret=is_win(board, ROW, COL);
		if (ret != 'C') {
			break;
		}
	}
	if (ret == '*') {
		printf("恭喜,玩家获胜!\n");
	}
	else if (ret == '#') {
		printf("大人,胜败乃兵家常事,下次赢回来吧!\n");
	}
	else if(ret=='Q'){
		printf("平局,旗鼓相当的对手!\n");
	}
}

写到这里,我们的三子棋也就完成啦,最后附上完整代码,希望各位有所收获

//game.h
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3

//初始化棋盘
void init_board(char board[ROW][COL],int row,int col);

//打印棋盘
void print_board(char board[ROW][COL],int row,int col);

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

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

//胜负判断
char is_win(char board[ROW][COL], int row, int col);

//game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化
void init_board(char board[ROW][COL], int row, int col) {
	int i;
	for (i = 0; i < row; i++) {
		int j = 0;
		for (j = 0; j < col; j++) {
			board[i][j] = ' ';
		}
	}
}

//打印棋盘
void print_board(char board[ROW][COL], int row, int col) {
	int i;
	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 < col - 1) {
			for (j = 0; j < col; j++) {
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

//玩家下棋
void player_move(char board[ROW][COL], int row, int col) {
	printf("玩家下棋,请选择坐标:\n");
	int x, y;
	do {
		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");
		}
	} while (1);
}

//电脑下棋
void computer_move(char board[ROW][COL], int row, int col) {
	printf("电脑下棋:\n");
	while (1) {
		int x = rand() % ROW;
		int y = rand() % COL;
		if (board[x][y] == ' ') {
			board[x][y] = '#';
			break;
		}
	}
}

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][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[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) == 1) {
		return 'Q';
	}
	return 'C';
}
//test.c
#include "game.h"
void menu() {
	printf("*************************\n");
	printf("*******1.  play   *******\n");
	printf("*******0.  exit   *******\n");
	printf("*************************\n");
}

void game() {
	char board[ROW][COL];
	init_board(board, ROW, COL);
	print_board(board, ROW, COL);
	char ret;
	while (1) {
		player_move(board, ROW, COL);
		print_board(board, ROW, COL);
		ret=is_win(board, ROW, COL);
		if (ret != 'C') {
			break;
		}
		computer_move(board, ROW, COL);
		print_board(board, ROW, COL);
		ret=is_win(board, ROW, COL);
		if (ret != 'C') {
			break;
		}
	}
	if (ret == '*') {
		printf("恭喜,玩家获胜!\n");
	}
	else if (ret == '#') {
		printf("大人,胜败乃兵家常事,下次赢回来吧!\n");
	}
	else if(ret=='Q'){
		printf("平局,旗鼓相当的对手!\n");
	}
}
void test() {
	srand((unsigned int)time(NULL));
	int input;
	do {
		menu();
		printf("请选择:\n");
		scanf("%d", &input);
		switch (input) {
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
		}
	} while (input != 0);
}
int main() {
	test();
	return 0;
}

如有错误,还请指正。

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值