【c语言版】带你领悟多子棋游戏

三子棋以及N子棋的实现

  • 初始化棋盘
  • 打印棋盘
  • 玩家下棋
  • 电脑下棋
  • 判断输赢
  • 主函数的实现(test.c)
  • game.c的实现
  • game.h的实现

铁汁们~今天给大家分享一篇三子棋以及N子棋的实现,来吧,开造⛳️

实现流程:
1.游戏不退出,继续玩下一把(循环);
2.应用多文件的形式写代码(玩游戏实现过程),包含初始化棋盘、打印棋盘、玩家下棋、电脑下棋、判断输赢操作。

初始化棋盘

思路:初始化棋盘为空格
需要遍历棋盘(二维数组),采用双重for循环来分别控制行、列。

void InitBoard(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] = ' ';
		}
	}
}

打印棋盘

版本1:
缺点:因为初始化棋盘为空格,直接遍历棋盘,打印棋盘,全为空格(空格在屏幕上不显示)。

void print(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]);
		}
		printf("\n");
	}
}

【c语言版】带你领悟多子棋游戏_第1张图片
版本2:
缺点:若要实现多子棋,该版本不能完成,只适用于三子棋的打印(受限制)。

void print(char board[Row][Col], int row, int col)
{
	int i = 0;
	for(i = 0; i < row; i++)
	{
			printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);//打印数据
			if (i < row - 1)
				printf("---|---|---\n");//打印分割线
	}
}

【c语言版】带你领悟多子棋游戏_第2张图片
正确的版本(版本三)
思路:用双层for循环来遍历二维数组(共使用三个for循环),第一层for循环来控制’打印数据行加分割行’总次数,第二个for循环来控制数据行的打印(每次都打印‘空格数据空格|’),第三个for循环来控制打印分割行的打印(每次打印’—|')。
【c语言版】带你领悟多子棋游戏_第3张图片

void print(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 < col - 1)  //前提条件
		{
			j = 0;  //打印分割线
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

【c语言版】带你领悟多子棋游戏_第4张图片

玩家下棋

思路:输入坐标,判断下标是否合法,不合法,重新输入,合法时还需判断该坐标处是否已经被落子。

void PlayMove(char board[Row][Col], int row, int col)
{
	printf("玩家输入\n");
	int x = 0;  
	int y = 0;
	while (1) //玩家要进行多次下棋(循环)
	{
		printf("请输入下棋的坐标,中间以空格隔开>:");
		scanf("%d %d", &x, &y);  
		if (x <= row && y <= col && x >= 1 && y >= 1)  //判断下标是否合法
		{                                      //合法
			if (board[x - 1][y - 1] ==' ')  //判断是否能落子
			{                               //能落子
				board[x - 1][y - 1] = '*';
				break;
			}
			else                          //不能落子
			{
				printf("坐标被占用,不能落子,请重新输入\n");
			}
		}
		else           //下标不合法
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

注意:0

【c语言版】带你领悟多子棋游戏_第5张图片

电脑下棋

思路:电脑产生随机坐标值,在判断坐标值是否合法,不合法无需做任何操作。

void ComputerMove(char board[Row][Col], int row, int col)
{
	printf("电脑输入\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % 3;  //rand函数产生随机数,rand()%3产生的数值范围为0~2,需要调用srand函数
		y = rand() % 3;
		if (board[x][y] == ' ')  //判断下标是否合法
		{                        //合法
			board[x][y] = '#';
			break;
		}
	}
}

【c语言版】带你领悟多子棋游戏_第6张图片

判断输赢

情况种类:四种情况:玩家赢,返回’*‘、 电脑赢,返回’#‘、 平局(电脑玩家均没赢,但棋盘已满),返回‘q’、 继续(电脑玩家均没赢,但棋盘未满),返回’c’.

三子棋判断输赢思路:分别进行行、列、正对角线以及负对角线的遍历,从而判断输赢。
正对角线i和j相同、负对角线i+j=row-1。

char Winner(char board[Row][Col], int row, int col)
{
	    int i = 0;
		for (i = 0; i < row; i++) //行
		{
			if (board[i][0] == board[i][1] && board[i][2] == board[i][1] && board[i][0] != ' ')
				return board[i][0];
		}
		i = 0;
		for (i = 0; i < col; i++) //列
		{
			if (board[0][i] == board[1][i] && board[2][i] == board[1][i] && board[0][i] != ' ')
				return board[0][i];
		}
		if (board[0][0] == board[1][1] && board[0][0] == board[2][2]&& board[0][0] != ' ')  //正对角线
			return board[0][0];
		if (board[0][2] == board[1][1] && board[0][2] == board[2][0]&& board[0][2] != ' ') //负对角线
			return board[0][2];
		if (isfull(board, row, col)) //平局
		{
			return 'q'; 
		}
		else  //继续
		return 'c';
}

多子棋判断输赢思路:用双层循环遍历二维数组:处于对角线上所有元素相等时,相邻两元素相等的个数等于行数-1。
1.行的判断

第一层for循环来控制行数,第二层for循环来控制列数(循环变量<列数-1),每一行前一个元素与后一个元素进行比较,若在一行中有一对元素不相等,就跳出内层循环,出内层for循环的两种情况(已经‘有一行中各元素都相等且都不等于空格’或‘一行中各元素不相等’),而对于‘有一行中各元素都相等且都不等于空格’此情况,此时循环变量等于列数-1,直接返回该行中的最后一个元素。

2.列的判断

第一层for循环来控制列数,第二层for循环来控制行数(循环变量<行数-1) ,每一列前一个元素与后一个元素进行比较,若在一列中有一对元素不相等,就跳出内层循环,出内层for循环的两种情况(已经‘有一列中各元素都相等且都不等于空格’或‘一列中各元素不相等’),而对于‘有一列中各元素都相等且都不等于空格’此情况,此时循环变量等于行数-1,直接返回该列中的最后一个元素。

3.正对角线的判断

由观察可知,在正方体中处于正对角线的元素行数和列数相等,此时只需要行数和列数分别都加一就可以找到下一个元素,从而来遍历正对角线,前一个元素与后一个元素进行比较,创建一个计数器来记录相邻两元素相等的个数,每次两元素相等个数就加一,由于当正对角线上所有元素相等且不等于空格时,相邻两元素相等的个数等于行数-1,当出了循环只需判断计数器的个数是否等于行数-1且不等于空格,相等就直接返回正对角线上任意元素。

4.负对角线的判断:

由观察可知,在正方体中处于负对角线的元素行数加列数相等行数-1,此时只需要行数+1、列数-1就可以找到下一个元素,从而来遍历负对角线,前一个元素与后一个元素进行比较,创建一个计数器来记录相邻两元素相等的个数,每次两元素相等个数就加一,由于当负对角线上所有元素相等且不等于空格时,相邻两元素相等的个数等于行数-1,当出了循环只需判断计数器的个数是否等于行数-1且不等于空格,相等就直接返回正对角线上任意元素。

char Winner(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 - 1; j++)
		{
			if (board[i][j] != board[i][j + 1])//若一行中有一个不相等就跳出一行的循环
				break;
		}
		if (j == col - 1 && board[i][j] != ' ')//相等但不能为空格
			return board[i][j];
	}
	i = 0;//列
	for (i = 0; i < col; i++)
	{
		int j = 0;
		for (j = 0; j < row - 1; j++)
		{
			if (board[j][i] != board[j + 1][i])//若一列中有一个不相等就跳出一行的循环
				break;
		}
		if (j == row - 1 && board[j][i] != ' ')
			return board[j][i];
	}
	int count = 0;//用来记录对角线上相邻元素相等的个数
	i = 0;
	for (i = 0; i < row-1; i++)//对角线(\)
	{
		if (board[i][i] == board[i + 1][i + 1]&&board[i][i]!=' ')
		{
			count++;
		}
		if (count == row - 1)
			return board[i][i];
	}
	i = 0;//对角线(/)
	for (i = 0; i < row-1; i++)
	{
		int j = 0;
		for (j =col-1; j>=1;j--)
		{
			if (i + j ==row - 1)
			{
				if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
				{
					count++;
				}
				if (count == row - 1)
					return board[i][j];
			}
		}
	}

主函数的实现(test.c)

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menue()  //菜单栏
{
	printf("****************\n");
	printf("**** 1.play ****\n");
	printf("**** 0.exit ****\n");
	printf("****************\n");
}

void game()
{
	char board[Row][Col] = { 0 };//因在玩游戏过程中要进行数据的存储,采用Row*Col的二维数组进行存储有效数据
	InitBoard(board, Row, Col);
	char ret = 0;
	while (1)
	{
		PlayMove(board, Row, Col); //玩家下棋
		print(board, Row, Col);  //打印棋盘
		ret = Winner(board, Row, Col); //判断输赢
		if (ret != 'c')
			break;
		ComputerMove(board, Row, Col);  //电脑下棋
		print(board, Row, Col);  //打印棋盘
		ret = Winner(board, Row, Col); //判断输赢
		if (ret != 'c')
			break;
	}
	if (ret == '*')
		printf("玩家赢\n");
	else if (ret == '#')
		printf("电脑赢\n");
	else
		printf("平局\n");
}

int main()
{
	srand((unsigned int)time(NULL)); //产生随机数时函数的调用(rand->srand->time),srand函数调用#include头文件,time函数调用#include头文件
	int input = 0;
	do     //先进行菜单栏的选择,若玩完一把还想在玩->循环(do..while循环体执行次数比条件判断次数多一)
	{
		menue();
		printf("请选择<:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

game.c的实现

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(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(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 < col - 1)  //打印分割线
		{
			j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

void PlayMove(char board[Row][Col], int row, int col)  //玩家下棋
{
	printf("玩家输入\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入下棋的坐标,中间以空格隔开>:");
		scanf("%d %d", &x, &y);
		if (x <= row && y <= col && x >= 1 && y >= 1) //判断下标是否合法
		{
			if (board[x - 1][y - 1] == ' ')  //合法,判断是否能落子
			{
				board[x - 1][y - 1] = '*';//能落子
				break;
			}
			else    //不能落子
			{
				printf("坐标被占用,不能落子,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

void ComputerMove(char board[Row][Col], int row, int col)  //电脑下棋
{
	printf("电脑输入\n");
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % 3;  //产生随机坐标(合法)
		y = rand() % 3;
		if (board[x][y] == ' ')  //坐标为被占用
		{
			board[x][y] = '#';
			break;
		}
	}
}

int isfull(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++)
		{
			if (board[i][j] == ' ')  //没满
				return 0;
		}
	}
	return 1;  //满了
}

char Winner(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 - 1; j++)
		{
			if (board[i][j] != board[i][j + 1])//若一行中有一个不相等就跳出一行的循环
				break;
		}
		if (j == col - 1 && board[i][j] != ' ')//相等但不能为空格
			return board[i][j];
	}
	i = 0;//列
	for (i = 0; i < col; i++)
	{
		int j = 0;
		for (j = 0; j < row - 1; j++)
		{
			if (board[j][i] != board[j + 1][i])//若一列中有一个不相等就跳出一行的循环
				break;
		}
		if (j == row - 1 && board[j][i] != ' ')
			return board[j][i];
	}
	int count = 0;//用来记录对角线上相邻元素相等的个数
	i = 0;
	for (i = 0; i < row-1; i++)//对角线(\)
	{
		if (board[i][i] == board[i + 1][i + 1]&&board[i][i]!=' ')
		{
			count++;
		}
		if (count == row - 1)
			return board[i][i];
	}
	i = 0;//对角线(/)
	for (i = 0; i < row-1; i++)
	{
		int j = 0;
		for (j =col-1; j>=1;j--)
		{
			if (i + j ==row - 1)
			{
				if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
				{
					count++;
				}
				if (count == row - 1)
					return board[i][j];
			}
		}
	}

	/*for (i = 0; i < row; i++)  //三子棋的判断
	{
		if (board[i][0] == board[i][1] && board[i][2] == board[i][1] && board[i][0] != ' ')
			return board[i][0];
	}
	i = 0;
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[2][i] == board[1][i] && board[0][i] != ' ')
			return board[0][i];
	}
	if (board[0][0] == board[1][1] && board[0][0] == board[2][2]&& board[0][0] != ' ')
		return board[0][0];
	if (board[0][2] == board[1][1] && board[0][2] == board[2][0]&& board[0][2] != ' ')
		return board[0][2];
	*/
	if (isfull(board, row, col))  //平局的判断
	{
		return 'q';
	}
	return 'c';
}

game.h的实现

作用:用于存放声明自定义函数

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#define Row 3  //便于实现多子棋时,行、列的更改
#define Col 3
#include
#include
#include
void InitBoard(char board[Row][Col], int row, int col);
void print(char board[Row][Col], int row, int col);
void PlayMove(char board[Row][Col], int row, int col);
void ComputerMove(char board[Row][Col], int row, int col);
char Winner(char board[Row][Col], int row, int col);
int isfull(char board[Row][Col], int row, int col);
运行结果

【c语言版】带你领悟多子棋游戏_第7张图片

铁铁们,分支语句和循环语句就到此结束啦,请动动你们的手给作者点个鼓励吧,你们的鼓励就是我的动力✨✨✨
【c语言版】带你领悟多子棋游戏_第8张图片

你可能感兴趣的:(c语言,算法,游戏,排序算法)