C语言之三子棋(n子棋)-创新互联

目录

创新互联为企业级客户提高一站式互联网+设计服务,主要包括成都网站设计、做网站、app软件开发公司、小程序开发、宣传片制作、LOGO设计等,帮助客户快速提升营销能力和企业形象,创新互联各部门都有经验丰富的经验,可以确保每一个作品的质量和创作周期,同时每年都有很多新员工加入,为我们带来大量新的创意。 

前言:

一、程序框架

选择界面

1、主程序

2、框架搭接

二、游戏函数

棋盘模块

定义声明及调用

函数声明

函数实现

玩家模块

函数声明及调用

函数实现

电脑模块

函数声明及调用

函数实现

判断模块

函数声明及调用

函数实现

三、整体代码

test.c

game.c

game.h

四、效果演示


前言:

 小时候我们都玩过五子棋,就是在一个5*5的棋盘上进行落子分为红黑双方,谁第一个在棋盘上五子成线,谁就赢得比赛 图示如下:

对于这样一个小游戏 我们用c语言该如何实现呢?那我们就要对这个游戏的实现进行分析了,首先,想要下棋我们得有一个棋盘,我们可以用二维数组来表示,棋盘是有了,那实现正常的博弈下棋,应该具备哪些模块呢,分析如下:

  1. 棋盘显示模块;
  2. 玩家下棋模块;
  3. 电脑下棋模块;
  4. 判断输赢模块;

我们只要把整体框架写好,保证衔接没问题,剩下就是子程序的实现啦 让我们一起试试吧


一、程序框架

我们既然学过了函数,数组,以及各个基础知识,那我们就不能停留在 所有函数都集中在一个main函数中那么low了,这次的三子棋,就让它 高大上一点,我们把函数声明,我们把函数的声明,放在头文件game .h中,游戏部分放在游戏的源文件game.c中,我们在函数test.c中,依次调用即可,显得程序逻辑清晰,简单明了。

选择界面 1、主程序

我们将实现部分集成在test.c函数中 在主程序main()调用

int main()
{
	test();
	return 0;
}
2、框架搭接

小时候玩的小霸王,都会有一个 界面拱玩家选择 是否 选择进入游戏,或退出,游戏肯定是不能玩一下就结束,所以我们要循环起来,还得要定义一个玩家选择的变量input,因为不同的选择,去向不同 所以用switch分支;因为首先就得出现选择界面,所以用do while 循环语句,来实现,代码实现如下:

void menu()
{
	printf("****************************************\n");
	printf("************  1.play  ******************\n");
	printf("************  0.exit  ******************\n");
	printf("****************************************\n");
}
void test()
{
	int input;
	do
	{
	 menu();
	 printf("请输入数字->");
	 scanf("%d",&input);

	 switch (input)
	 {
	 case 1:
		 game();
		 break;
	 case 0:
		 printf("欢迎下次来玩\n");
		 break;
	 default:
		 printf("输入错误,请重新输入\n");
		 break;
	 }

	
	} while (input);

二、游戏函数

当玩家进入选择进入游戏后,我们就要有棋盘显示,玩家 和电脑就要开始玩起来了,具体game()函数分析如下

棋盘模块

我们需要定义一个棋盘,五子棋我们就五行五列 三子棋就三行三列,所以为了方便修改,我们要define行列,并将他们放在game.h头文件中,还需要将棋盘初始化,并显示出来 具体代码如下:

定义声明及调用
#define ROW  5
#define COL  5
//定义一个三行三列的数组(棋盘),用来存放棋子
	char board[ROW][COL];
	char ret = 0;//判断是下棋结果的变量
	//初始化棋盘
	init_board( board, ROW, COL);
	//屏幕上显示棋盘
    print_board(board, ROW, COL);

之前我们提过 我们会在test.c中调用子程序,在game.c写具体实现方法,那棋盘初始化,以及显示应该怎么实现呢,棋盘刚开始出现的时候 我们应该保证棋盘上没人落子,所以初始状态是空白,但是我们也看到了 棋盘是有边框的 所以我们在棋盘显示函数中 应该让边框显示出来。学过二维数组的我们 应该觉得很简单,初始化函数无非是把棋盘上每个元素 初始化为空格,显示函数也就是打印边框,具体代码如下:

函数声明
//初始化三子棋
void init_board(char board[ROW][COL],int row,int col);
//打印三子棋
void print_board(char board[ROW][COL], int row, int col);
函数实现
//实现棋盘初始化
void init_board(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i< row; i++)
	{
		for (int j = 0; j< col; j++)
		{
			board[i][j] = ' ';

		}
	}

}
//实现棋盘显示
void print_board(char board[ROW][COL], int row, int col)
{

	for (int i = 0; i< row; i++)
	{
		for (int j = 0; j< col; j++)
		{
			printf(" %c ",board[i][j]);
			if(j<(col -1))
			printf("|");
		}
		printf("\n");
		//考虑三子棋最后一个没有打印行
		if (i< row - 1)
		{
			for (int j = 0; j< col; j++)
			{

				printf("___");
				if (j< col - 1)
					printf("|");

			}
		}
		printf("\n");
	}
}
玩家模块

棋盘搭接好啦,那就开始下吧,在玩家下棋的子程序中,就是落子,然后棋盘显示,所以就是写一个玩家下棋的函数 之后,调用一下显示函数

函数声明及调用
void player_mover(char board[ROW][COL], int row, int col);
//玩家开始下棋
		player_mover(board, ROW, COL);
		print_board(board, ROW, COL);
函数实现

玩家下棋,就是选择我们想要下的位置 对应棋盘上的二维坐标,生活中我们不可能在棋盘外落子,或者在一个已经落完棋子的地方落子,所以我们要对落子进行判断,当棋盘是空白,我们就可以落子(我们用*代表玩家),如果有棋子了 我们要提示该位置已经被落子,并让他重新落子,如果胡乱选择棋盘外,我们要提醒非法落子并让他重新落子,因为有重新落子,所以我们也需要将玩家下棋的步骤,写进循环中,具体代码如下:

//玩家开始下棋
void player_mover(char board[ROW][COL], int row, int col)
{
	printf("请玩家落子\n");
	while (1)
	{
		int x = 0;
		int	y = 0;		
		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");
	}

}
电脑模块

 跟玩家类似,在game.c中实现电脑下棋,主程序中调用,然后再调用显示函数

函数声明及调用
//电脑开始下棋
void computer_mover(char board[ROW][COL], int row, int col);
//电脑开始下棋
		computer_mover(board, ROW, COL);
		print_board(board, ROW, COL);
函数实现

因为是电脑落子,所以数字要是随机的,随机数字的实现要用到时间戳 srand、rand函数,随机生成 棋盘上的行列限制的数字,这里不做细讲,我课余时间会补充一起,贴上链接;形成一个坐标之后,我们也要进行相同判断,是否已经落子,具体代码如下:

//电脑开始下棋
void computer_mover(char board[ROW][COL], int row, int col)
{
	printf("电脑落子\n");
	while (1)
	{
	    int x = rand() % row;//随机生成 0 --row-1 的数字
		int y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
判断模块

正常生活中我们玩游戏的时候,下完一次,我们就要去检查,有没有连珠,是我们赢啦,还是电脑赢了 所以每次玩家落完子,或者电脑落完子,我们都要进行一次判断,所以我们需要有一个判断函数,定义个变量接收返回值 并通过返回值判断谁赢。

函数声明及调用
//判断输赢
 char is_win(char board[ROW][COL], int row, int col);

我们定义当返回值为C时候,游戏继续,说明没有分出胜负,当返回值为*玩家赢,返回值为#电脑赢,如果,当棋盘棋子填满,还无法判定胜负时候,就判断为平齐。

while (1)
	{
		//玩家开始下棋
		player_mover(board, ROW, COL);
		print_board(board, ROW, COL);
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
			break;

		//电脑开始下棋
		computer_mover(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
		printf("平局\n");
}
函数实现

判断输赢,其实考虑的要很多,要判断行、判断列、判断对角线,并将连城线上对应棋盘上的棋子返回,就可以做到判断是电脑赢 还是玩家赢了,棋盘的大小会不同,行列也会对应的进行改变,所以我的判断函数部分,用的是两层for循环,判断,前后元素是否相同,相同计数加一,然后最后都相同的的话,计数会比列数少一,我们依此为判断依据 ,最难想的应该是右上到左下角的对角线判断 我当初是这样想的,对角线 三子棋的话 坐标分别是(0,2)(1,1)(2,0)我发现 行坐标自增1,列坐标就自减1,利用这个规律,就可以讲对角线表示出来上代码 清晰明了:

//判断输赢
char is_win(char board[ROW][COL], int row, int col)
{
	//判断行
	for (int i = 0; i< row; i++)
	{
		int count0 = 0;
		for (int j = 0; j< col - 1; j++)
		{
			if (board[i][j] == board[i][j + 1] && board[i][j] != ' ')
			{
				count0++;
			}
		}
		if (count0 == col - 1)
		{
			return board[i][0];
		}
	}
	//判断列
	for (int i = 0; i< row; i++)
	{
		int count1 = 0;
		for (int j = 0; j< col - 1; j++)
		{
			if (board[j][i] == board[j+1][i] && board[j][i] != ' ')
			{
				count1++;
			}
		}
		if (count1 == col - 1)
		{
			return board[0][i];
		}
	}
	// 判断左上到右下的对角线
	int count2 = 0;
	for (int i = 0; i< row - 1; i++)
	{
	
		if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' ')
		{
			count2++;
		}
	}
	if (count2 == col - 1)
	{
		return board[0][0];
	}

	// 判断右上到左下
	int count3 = 0;

		for (int i = 0;i

最后差一步判断是否平局呢,我们单独写一个 平局函数,并只在game.c中调用,就记录棋盘有没有满,没满就继续比赛,满了 就平局,代码如下:

char is_win(char board[ROW][COL], int row, int col)
{
	//判断行
	for (int i = 0; i< row; i++)
	{
		int count0 = 0;
		for (int j = 0; j< col - 1; j++)
		{
			if (board[i][j] == board[i][j + 1] && board[i][j] != ' ')
			{
				count0++;
			}
		}
		if (count0 == col - 1)
		{
			return board[i][0];
		}
	}

	if (is_full(board, row, col) == 1)
	{
		return 'Q';
	}

	//继续
	//没有玩家或者电脑赢,也没有平局,游戏继续
	return 'C';
}

三、整体代码 test.c
#define _CRT_SECURE_NO_WARNINGS 1
// **************三子棋游戏*******************************//

#include "gaem.h"


void game()
{
	//定义一个三行三列的数组(棋盘),用来存放棋子
	char board[ROW][COL];
	char ret = 0;//判断是下棋结果的变量
	//初始化棋盘
	init_board( board, ROW, COL);
	//屏幕上显示棋盘
    print_board(board, ROW, COL);
	while (1)
	{
		//玩家开始下棋
		player_mover(board, ROW, COL);
		print_board(board, ROW, COL);
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
			break;

		//电脑开始下棋
		computer_mover(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
		printf("平局\n");
}
void menu()
{
	printf("****************************************\n");
	printf("************  1.play  ******************\n");
	printf("************  0.exit  ******************\n");
	printf("****************************************\n");
}
void test()
{
	srand((unsigned) time(NULL));
	int input;
	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;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1

#include "gaem.h"
// 实现初始化棋盘
void init_board(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i< row; i++)
	{
		for (int j = 0; j< col; j++)
		{
			board[i][j] = ' ';

		}
	}

}
//实现棋盘显示
void print_board(char board[ROW][COL], int row, int col)
{

	for (int i = 0; i< row; i++)
	{
		for (int j = 0; j< col; j++)
		{
			printf(" %c ",board[i][j]);
			if(j<(col -1))
			printf("|");
		}
		printf("\n");
		//考虑三子棋最后一个没有打印行
		if (i< row - 1)
		{
			for (int j = 0; j< col; j++)
			{

				printf("___");
				if (j< col - 1)
					printf("|");

			}
		}
		printf("\n");
	}
}

//玩家开始下棋
void player_mover(char board[ROW][COL], int row, int col)
{
	printf("请玩家落子\n");
	while (1)
	{
		int x = 0;
		int	y = 0;		
		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");
	}

}
//电脑开始下棋
void computer_mover(char board[ROW][COL], int row, int col)
{
	printf("电脑落子\n");
	while (1)
	{
	    int x = rand() % row;//随机生成 0 --row-1 的数字
		int y = rand() % col;

		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

static int is_full(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 is_win(char board[ROW][COL], int row, int col)
{
	//判断行
	for (int i = 0; i< row; i++)
	{
		int count0 = 0;
		for (int j = 0; j< col - 1; j++)
		{
			if (board[i][j] == board[i][j + 1] && board[i][j] != ' ')
			{
				count0++;
			}
		}
		if (count0 == col - 1)
		{
			return board[i][0];
		}
	}
	//判断列
	for (int i = 0; i< row; i++)
	{
		int count1 = 0;
		for (int j = 0; j< col - 1; j++)
		{
			if (board[j][i] == board[j+1][i] && board[j][i] != ' ')
			{
				count1++;
			}
		}
		if (count1 == col - 1)
		{
			return board[0][i];
		}
	}
	// 判断左上到右下的对角线
	int count2 = 0;
	for (int i = 0; i< row - 1; i++)
	{
	
		if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' ')
		{
			count2++;
		}
	}
	if (count2 == col - 1)
	{
		return board[0][0];
	}

	// 判断右上到左下
	int count3 = 0;

		for (int i = 0;i
game.h
#define ROW  5
#define COL  5

#include#include#include//初始化三子棋
void init_board(char board[ROW][COL],int row,int col);
//打印三子棋
void print_board(char board[ROW][COL], int row, int col);

//玩家下棋
void player_mover(char board[ROW][COL], int row, int col);
//电脑开始下棋
void computer_mover(char board[ROW][COL], int row, int col);
//判断输赢
 char is_win(char board[ROW][COL], int row, int col);

四、效果演示

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


本文题目:C语言之三子棋(n子棋)-创新互联
文章源于:http://scyanting.com/article/igdgi.html