C语言实现三子棋(井字棋)

目录

思路

实现

1.游戏菜单

1.1 打印游戏菜单

1.2 玩家自主选择

2.设置游戏函数

2.1 声明并且定义一个二维数组

2.2 初始化二维数组

3.打印棋盘 

4. 下棋

4.1 玩家下棋

4.2 电脑下棋

5.判断输赢

6. 组合所有步骤


思路

1.设置一个游戏菜单,让玩家可以自主选择开始游戏或者退出游戏。

2.声明并定义一个二维数组,用来存放棋子。

3.打印一个棋盘,将棋子的布局展示出来。

4.玩家下棋,电脑下棋

5.判断输赢

实现

首先我们打开我们的Visual Studio,创建一个项目

为了代码的简洁性和方便我们调试代码,我们在这里创建了一个头文件,两个源文件

接下来我们开始编写程序一步步实现我们的三子棋。

1.游戏菜单

1.1 打印游戏菜单

首先我们可以使用printf函数打印出一个相对精美的游戏菜单

代码如下:

//test.c

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

void test()
{
	menu();//打印游戏菜单
}

int main()
{
	test();
	return 0;
}

1.2 玩家自主选择

        我们要做到玩家自主选择玩还是不玩,可以引入一个input变量来接受玩家键入的值,然后再通过switch语句来分别作出对应的操作。

        同时,如果玩家玩一次不过瘾想要接着玩,我们这时候就需要一个循环语句来实现,我们可以发现,菜单一开始肯定是要打印出来的,所以是先做一次再判断,我们用do...while语句来实现这个功能。

代码如下:

//test.c

#include <stdio.h>

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

void test()
{
	int input = 0;
	do
	{
		menu();//打印游戏菜单
		printf("请做出你的选择:>");//提示输入
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("三子棋");//先调试看代码能不能运行,能运行后再写真正的游戏
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");//如果输入0和1以外的数字,则重新输入
			break;
		}
	} while (input);//input为0跳出循环游戏结束,input不为0再次进入循环进行选择
}

int main()
{
	test();
	return 0;
}

2.设置游戏函数

        为了代码的简洁性,我们封装一个game()函数来实现三子棋游戏主体。

2.1 声明并且定义一个二维数组

        玩家下棋和电脑下棋均需要一个东西来存放我们的棋子,那这时候我们就需要引入一个二维数组来存放棋子,因为我们需要的三子棋,所以我们定义一个3*3的二维数组即可,当然,为了后续我们可以升级成N子棋,我们可以在game.h文件中利用#define定义的常量标识符来充当行和列,届时我们只需要修改ROWCOL的值就可以把三子棋改成N子棋。

        代码如下:

//game.h
//因为在test.c文件中引入了头文件,所以#include stdio.h就可以放在这个头文件中
#include <stdio.h>  

//定义行和列
#define ROW 3
#define COL 3

//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] = { 0 };//声明并定义一个数组来存放棋子
}

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");//如果输入0和1以外的数字,则重新输入
			break;
		}
	} while (input);//input为0跳出循环游戏结束,input不为0再次进入循环进行选择
}

int main()
{
	test();
	return 0;
}

2.2 初始化二维数组

        先让我们看看棋盘:

        我们可以看到,棋盘由字符'|'与字符'-'组合而成,而每个格子中是棋子(未下的地方是空格)

所以我们就需要初始化一下二维数组,使其全为' ',来达到我们的目的。

        接下来我们就需要定义函数分别实现二维数组的初始化。

        代码如下:

//test.c
void game()
{
	char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
	init_board(board, ROW, COL);
}

//game.h
//初始化二维数组
void init_board(char* board[ROW][COL], int row, int col);


//game.c
#include "game.h"//注意包含头文件

//初始化二维数组
void init_board(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] = ' ';//将二维数组中每个元素初始化为' '
		}
	}
}

3.打印棋盘 

        先让我们看看棋盘:

        我们可以看到,棋盘由字符'|'与字符'-'组合而成所以我们可以通过printf函数来打印我们的棋盘。

        代码如下:

//test.c
void game()
{
	char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
	init_board(board, ROW, COL);
    print_board(board, ROW, COL);
}

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

//game.c
#include "game.h"//注意包含头文件


//打印棋盘
void print_board(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)//最后一行不需要打印
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)//最后一个'|'不需要打印
					printf("|");
			}
			printf("\n");
		}
	}
}

4. 下棋

4.1 玩家下棋

        在设计玩家下棋函数之前,我们要知道,普通玩家是没有我们程序员的思维的,他们不知道棋盘的第1行其实是“第0行”,第1列其实是“第0列”,所以我们需要迎合玩家思维,那么如何实现呢?

        代码如下:

//test.c
void game()
{
	char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
	//初始化二维数组
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);
	//玩家移动
	player_move(board, ROW, COL);
	print_board(board, ROW, COL);//下完棋后打印棋盘
}

//game.h
//玩家移动
void player_move(char board[ROW][COL], int row, int col);

//game.c
void player_move(char board[ROW][COL], int row, int col)
{
	int x = 0, 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] = '*';//行数-1和列数-1即为数组中的行下标和列下标
				break;
			}
			else
				printf("该位置已有棋子,请重新选择!!!\n");
		}
		else
			printf("输入坐标有误,请重新输入!!!\n");
	}
}

4.2 电脑下棋

        电脑下棋就没有玩家下棋的前提,因为电脑知道棋盘的第1行其实是“第0行”,第1列其实是“第0列”,但是我们需要生成随机数,这就要用到rand()函数、srand()函数和time()函数,而这三个库函数分别要引入<stdlib.h>头文件和<time.h>头文件这里就不做过多讲解,可以自行查找。

        代码如下:

//test.c
void game()
{
	char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
	//初始化二维数组
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);
	//玩家移动
	player_move(board, ROW, COL);
	print_board(board, ROW, COL);//下完棋后打印棋盘
	//电脑移动
	computer_move(board, ROW, COL);
}

//game.h
//电脑移动
void computer_move(char board[ROW][COL], int row, int col);

//game.c
void computer_move(char board[ROW][COL], int row, int col)
{
	while (1)
	{
		//生成随机数
		int x = rand() % 3;
		int y = rand() % 3;
		if (board[x][y] == ' ')//如果这个位置已经有棋子就重新生成随机数
		{
			board[x][y] = '#';
			break;
		}
	}
}

5.判断输赢

        我们可以看看上面的代码,玩家和电脑各下完一次棋游戏就结束了,这很明显不对,我们需要让他们不断的下棋,直到分出胜负,所以我们需要一个循环来保证游戏的正常进行,棋盘每落下一个棋子就要用到一个判断输赢的函数来打断循环。

        代码如下:

//test.c
void game()
{
	char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
	char ret = 0;
	//初始化二维数组
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);
	while (1)
	{
		//玩家移动
		player_move(board, ROW, COL);
		print_board(board, ROW, COL);//下完棋后打印棋盘
		ret = is_win(board, ROW, COL);//判断输赢
		//'*'代表玩家胜利
		//'#'代表电脑胜利
		//'Q'代表平局
		//'C'代表游戏继续
		if (ret != 'C')//不等于'C'游戏结束,跳出循环
			break;
		//电脑移动
		computer_move(board, ROW, COL);
		print_board(board, ROW, COL);
		ret = is_win(board, ROW, COL);
		is_win(board, ROW, COL);//判断输赢
		if (ret != 'C')//不等于'C'游戏结束,跳出循环
			break;
	}
	if (ret == 'Q')
		printf("平局\n");
	else if (ret == '*')
		printf("玩家胜利\n");
	else if (ret == '#')
		printf("电脑胜利\n");
}

//game.h
//判断输赢
char is_win(char board[ROW][COL], int row, int col);

//game.c
char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	//行相等
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col - 1; j++)
		{
			if (board[i][j] != board[i][j + 1] || board[i][j] == ' ')
				break;
		}
		if (j == col - 1)
			return board[i][j];
	}
	//列相等
	for (j = 0; j < col; j++)
	{
		for (i = 0; i < row - 1; i++)
		{
			if (board[i][j] != board[i + 1][j] || board[i][j] == ' ')
				break;
		}
		if (i == row - 1)
			return board[i][j];
	}
	//正对角线相等
	for (i = 0; i < row - 1; i++)
	{
		j = i;
		if (board[i][j] != board[i + 1][j + 1] || board[i][j] == ' ')
			break;
	}
	if (i == col - 1)
		return board[i][j];
	//反对角线相等
	for (i = 0; i < row - 1; i++)
	{
		j = col - 1 - i;
		if (board[i][j] != board[i + 1][j - 1] || board[i][j] == ' ')
			break;
	}
	if (i == row - 1)
		return board[i - 1][j];
	//平局
	for (i = 0; i < row; i++)
	{
		for (j = 0; i < col; j++)
		{
			if (board[i][j] == ' ')
				break;
		}
	}
	if (i == row && j == col)
		return 'Q';
	else
		return 'C';
}

6. 组合所有步骤

        我们把三子棋的实现细化为5个步骤,现在让我们把他们整合起来

最终我们得到了三子棋代码:

分文件展示:

game.h:

#define _CRT_SECURE_NO_WARNINGS 1

//因为在test.c文件中引入了头文件,所以#include stdio.h就可以放在这个头文件中
#include <stdio.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);

test.c:

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h" //这里我们需要引用一下头文件

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

void game()
{
	char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
	char ret = 0;
	//初始化二维数组
	init_board(board, ROW, COL);
	//打印棋盘
	print_board(board, ROW, COL);
	while (1)
	{
		//玩家移动
		player_move(board, ROW, COL);
		print_board(board, ROW, COL);//下完棋后打印棋盘
		ret = is_win(board, ROW, COL);//判断输赢
		//'*'代表玩家胜利
		//'#'代表电脑胜利
		//'Q'代表平局
		//'C'代表游戏继续
		if (ret != 'C')//不等于'C'游戏结束,跳出循环
			break;
		//电脑移动
		computer_move(board, ROW, COL);
		print_board(board, ROW, COL);
		ret = is_win(board, ROW, COL);
		is_win(board, ROW, COL);//判断输赢
		if (ret != 'C')//不等于'C'游戏结束,跳出循环
			break;
	}
	if (ret == 'Q')
		printf("平局\n");
	else if (ret == '*')
		printf("玩家胜利\n");
	else if (ret == '#')
		printf("电脑胜利\n");
}

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");//如果输入0和1以外的数字,则重新输入
			break;
		}
	} while (input);//input为0跳出循环游戏结束,input不为0再次进入循环进行选择
}

int main()
{
	test();
	return 0;
}

game.c:

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void init_board(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 print_board(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)//最后一行不需要打印
		{
			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)
{
	int x = 0, 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] = '*';//行数-1和列数-1即为数组中的行下标和列下标
				break;
			}
			else
				printf("该位置已有棋子,请重新选择!!!\n");
		}
		else
			printf("输入坐标有误,请重新输入!!!\n");
	}
}

void computer_move(char board[ROW][COL], int row, int col)
{
	while (1)
	{
		//生成随机数
		int x = rand() % 3;
		int y = rand() % 3;
		if (board[x][y] == ' ')//如果这个位置已经有棋子就重新生成随机数
		{
			board[x][y] = '#';
			break;
		}
	}
}

char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	//行相等
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col - 1; j++)
		{
			if (board[i][j] != board[i][j + 1] || board[i][j] == ' ')
				break;
		}
		if (j == col - 1)
			return board[i][j];
	}
	//列相等
	for (j = 0; j < col; j++)
	{
		for (i = 0; i < row - 1; i++)
		{
			if (board[i][j] != board[i + 1][j] || board[i][j] == ' ')
				break;
		}
		if (i == row - 1)
			return board[i][j];
	}
	//正对角线相等
	for (i = 0; i < row - 1; i++)
	{
		j = i;
		if (board[i][j] != board[i + 1][j + 1] || board[i][j] == ' ')
			break;
	}
	if (i == col - 1)
		return board[i][j];
	//反对角线相等
	for (i = 0; i < row - 1; i++)
	{
		j = col - 1 - i;
		if (board[i][j] != board[i + 1][j - 1] || board[i][j] == ' ')
			break;
	}
	if (i == row - 1)
		return board[i - 1][j];
	//平局
	for (i = 0; i < row; i++)
	{
		for (j = 0; i < col; j++)
		{
			if (board[i][j] == ' ')
				break;
		}
	}
	if (i == row && j == col)
		return 'Q';
	else
		return 'C';
}

好了,以上就是三子棋的实现,让我们下篇文章再会!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值