C语言之三子棋(n子棋)

目录

前言:

一、程序框架

选择界面

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<row -1;i++)
		{
			if (board[i][row - i - 1] == board[i + 1][row - i - 2] && board[i][row - i - 1] != ' ')
			{
				count3++;
			}

		}
		if (count3 == col - 1)
		{
			return board[0][row - 1];
		}

最后差一步判断是否平局呢,我们单独写一个 平局函数,并只在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<row -1;i++)
		{
			if (board[i][row - i - 1] == board[i + 1][row - i - 2] && board[i][row - i - 1] != ' ')
			{
				count3++;
			}

		}
		if (count3 == col - 1)
		{
			return board[0][row - 1];
		}
	

	//int i = 0;
	判断三行
	//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';
}

game.h

#define ROW  5
#define COL  5

#include<stdio.h>
#include<stdlib.h>
#include<time.h>



//初始化三子棋
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);

四、效果演示

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值