C语言实现三子棋(N子棋)

目录

1.游戏规则

2.游戏实现

3.游戏测试

4.代码链接

---------------------------------------------------------------------------------------------------------------------------------

1.游戏规则

        三子棋又称井字棋,一般来说是在一个3×3的棋盘中,双方执不同的棋按先后顺序依次落子,率先将棋连成连续3个(同一种棋连成一行或者一列,或者斜对角)的一方获胜,如下图所示,红方为先行方,红方率先将棋连成3子一线。

2.游戏实现

        首先我们将项目分为游戏和测试两个模块,分别创建game.h game.c和test.c三个文件,game文件用于游戏的声明和实现,test模块用于游戏的测试。

        游戏的大致逻辑如下所示:

以上转换为代码:

//游戏测试模块
void test() {
	int input = 0;
	do {
		//打印菜单
		menu();

		//获取用户输入
		printf("请选择:>");
		scanf("%d", &input);

		//判断用户输入
		switch (input) {
		case 1:
			//进入游戏
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("非法输入,请重新输入\n");
			break;
		}
	} while (input);
}

//实现一个三子棋的游戏
int main() {
	test();
	return 0;
}

2.1打印菜单

        打印游戏菜单menu(),提示用户输入,1代表开始游戏,0表示推出游戏

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

2.2获取用户输入

        获取用户输入,根据输入判断是否执行游戏模块。

2.3执行游戏程序

        当用户输入1时,进入游戏模块game()。游戏执行后,应该先打印一张空的棋盘,用户输入坐标后,重新打印已经落子后的棋盘,接着电脑下棋,再打印棋盘,依次类推。同时,在一方落子后,需要判断棋面是哪一方赢,或者平局,或者棋还未下完,根据棋面状态决定继续下棋还是结束下棋。游戏的执行逻辑如下:

 2.3.1打印棋盘

        为了能够打印棋盘,首先创建棋盘并进行初始化,为了能够更灵活的复用代码,在game.h头文件中定义两个符号ROW和COL来分别代表棋盘数组的行和列,后续要改变棋盘的大小,只需要改变这两个量的值。

#define ROW 3
#define COL 3
//创建棋盘
char board[ROW][COL] = { 0 };

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

//打印棋盘
print_board(board, ROW, COL);

        为了能在终端上看的出来棋盘,首先将数组初始化为空格,即' ',并在相应的行和列打印横竖边界,打印的形式如下图所示:

        对应的代码:

//初始化棋盘
void init_board(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 print_board(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++) {
			printf(" %c ", board[i][j]);
			if (j < col - 1) {
				printf("|");
			}
		}
		printf("\n");
		if (i < row - 1) {
			for (j = 0; j < col; j++) {
				printf("---");
				if (j < col - 1) {
					printf("|");
				}
			}
		}
		printf("\n");
	}

}

        终端打印效果:

2.3.2玩家下棋

        能够顺利打印棋盘后,接下来是玩家进行下棋,首先获取玩家输入的坐标信息,得到输入坐标后需要判断坐标值是否有效,例如是否取值在设定的棋盘坐标大小之内,坐标判定有效后,仍需判定坐标所表示的地方是否已经下过棋,若下过棋,需要提示用户重新输入坐标,若没有,则将对应位置的内容改为玩家所下的棋,这里用字符 * 表示玩家下棋,字符 # 表示电脑下棋, 因为数组的下标从0开始,而玩家默认坐标是从1开始的,所以应该将输入的横纵坐标都减1后,才是需要更改的棋盘坐标。玩家下棋逻辑如下:

        代码: 

void player_turn(char board[ROW][COL], int row, int col) {
	int x = 0;
	int y = 0;
	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("坐标非法\n");
		}
	}
}
2.3.3 电脑下棋

        电脑下棋同理,通过获取0~棋盘大小的随机值,例如x=rand()%row,y=rand()%col,若row为3,即x的取值范围为0~2(注意,调用rand()函数我们需要给其指定sand(),即随机值起点,我们可以指定从当前时间开始,即srand((unsigned int)time(NULL));同样判断坐标值是否已经不是空格,若不是,修改对应位置值为字符 #。

2.3.4判断输赢

        双方各自下完棋后,需要打印更改后的棋盘,然后判断输赢。这里用字符 * 表示玩家赢,字符 # 表示电脑赢,字符 Q 表示平局,字符 C 表示棋未要玩,继续下棋,根据判断的结果返回相应的字符。

        一方赢的条件为3行或3列或斜对角连成3个相同形状的符号,例如可以先遍历棋盘数组,获取一行中的元素个数,将一行中的元素个数存放在一个arr[]数组中,数组的大小就是棋盘数组一行元素的个数,即棋盘数组的列数,存放入arr[]后再判断其中元素是否相等,若相等,再判断是字符 * 还是字符 #,若不相等,同理再获取每一列与对角元素,并进行比较。

        若以上判断没有结果,再判断棋盘是否已经被下满,即棋盘数组元素已经没有空格字符了,若被下满,则表示平局,返回字符 Q,若没有,则继续下棋。

//判断数组内元素是否相等
int is_equal(char arr[], int sz) {
	char ret = arr[0];
	for (int i = 1; i < sz; i++) {
		if (ret != arr[i]) {
			return 0;
		}
	}
	return 1;
}

//判断输赢
char is_win(char board[ROW][COL], int row, int col) {
	//获取每一行数据,判断是否相等
	for (int i = 0; i < row; i++) {
		char arr1[COL] = { 0 };
		for (int j = 0; j < col; j++) {
			arr1[j] = board[i][j];
		}
		if (1 == is_equal(arr1, col)) {
			if (arr1[0] == '*') {
				return '*';
			}
			else if (arr1[0] == '#') {
				return '#';
			}
		}
	}
	//获取每一列数据,判断是否相等
	for (int i = 0; i < row; i++) {
		char arr1[ROW] = { 0 };
		for (int j = 0; j < col; j++) {
			arr1[j] = board[j][i];
		}
		if (1 == is_equal(arr1, row)) {
			if (arr1[0] == '*') {
				return '*';
			}
			else if (arr1[0] == '#') {
				return '#';
			}
		}
	}
	//获取斜对角数据,判断是否相等,行和列需相等
	if (row == col) {
		char arr2[ROW] = { 0 };
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < row; j++) {
				if (i == j) {
					arr2[i] = board[i][j];
				}
			}
		}
		if (1 == is_equal(arr2, row)) {
			if (arr2[0] == '*') {
				return '*';
			}
			else if (arr2[0] == '#') {
				return '#';
			}
		}

		char arr3[ROW] = { 0 };
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < row; j++) {
				if (i + j == row - 1) {
					arr3[i] = board[i][j];
				}
			}
		}
		if (1 == is_equal(arr3, row)) {
			if (arr3[0] == '*') {
				return '*';
			}
			else if (arr3[0] == '#') {
				return '#';
			}
		}
	}

	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			if (board[i][j] == ' ') {
				return 'C';
			}
		}
	}
	return 'Q';
}

最后根据返回的字符,打印相应的结果。 

3.游戏测试

        首先我们测试3×3的棋盘,编译并运行程序:

如果需要改变棋盘的大小,只需要改变符号ROW和COL的大小,例如改为4×4的棋盘:

#define ROW 4
#define COL 4

 

 4.代码链接

https://gitee.com/hkjz/for-c/tree/master/tic_tac_toe/tic_tac_toe

好的,我可以回答这个问题。以下是一个简单的C语言实现单人三子棋游戏的代码: ```c #include <stdio.h> #include <stdlib.h> #define BOARD_SIZE 3 void init_board(char board[][BOARD_SIZE]); void print_board(char board[][BOARD_SIZE]); int make_move(char board[][BOARD_SIZE], int row, int col, char player_char); int check_win(char board[][BOARD_SIZE], char player_char); int main() { char board[BOARD_SIZE][BOARD_SIZE]; int row, col, win; char player_char = 'X'; init_board(board); print_board(board); while (1) { printf("\nPlayer %c's turn.\n", player_char); printf("Enter row number: "); scanf("%d", &row); printf("Enter column number: "); scanf("%d", &col); if (make_move(board, row, col, player_char)) { print_board(board); win = check_win(board, player_char); if (win) { printf("\nPlayer %c wins!\n", player_char); break; } player_char = (player_char == 'X') ? 'O' : 'X'; } else { printf("Invalid move. Try again.\n"); } } return 0; } void init_board(char board[][BOARD_SIZE]) { int i, j; for (i = 0; i < BOARD_SIZE; i++) { for (j = 0; j < BOARD_SIZE; j++) { board[i][j] = '-'; } } } void print_board(char board[][BOARD_SIZE]) { int i, j; printf("\n"); for (i = 0; i < BOARD_SIZE; i++) { for (j = 0; j < BOARD_SIZE; j++) { printf("%c ", board[i][j]); } printf("\n"); } } int make_move(char board[][BOARD_SIZE], int row, int col, char player_char) { if (row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE || board[row][col] != '-') { return 0; } board[row][col] = player_char; return 1; } int check_win(char board[][BOARD_SIZE], char player_char) { int i, j; int row_win, col_win, diag_win1, diag_win2; for (i = 0; i < BOARD_SIZE; i++) { row_win = 1; col_win = 1; for (j = 0; j < BOARD_SIZE; j++) { if (board[i][j] != player_char) { row_win = 0; } if (board[j][i] != player_char) { col_win = 0; } } if (row_win || col_win) { return 1; } } diag_win1 = 1; diag_win2 = 1; for (i = 0; i < BOARD_SIZE; i++) { if (board[i][i] != player_char) { diag_win1 = 0; } if (board[i][BOARD_SIZE-1-i] != player_char) { diag_win2 = 0; } } if (diag_win1 || diag_win2) { return 1; } return 0; } ``` 这个程序实现了基本的单人三子棋游戏,并且包括了判断胜负的函数。您可以根据需要修改和扩展此代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值