人与人之间的单机五子棋 —— C语言实现

人与人之间的单机五子棋

在这里插入图片描述


每博一文案

作家苏曾说,到了现在这个年纪,谁都不想再取悦了,跟谁在一起舒服就和
谁在一起,包括朋友也是,累了,就躲远一点。人活着总是离不开圈子二字。
为了扩大自己的社交圈,参见各种活动,每天觥筹交错,忙得不亦乐乎?
可是,当我们心情低落的时候,把通讯录翻了个遍,也没找到一个能倾诉的人。
当我们遇到麻烦,想要求助,那些所谓的朋友,愿意帮忙的寥寥无几,以前
总觉得圈子越大越好,朋友越多越好。后来,慢慢发现,真正的朋友,再好,不再多。
越简单的人,越难交心,越简单的关系,越难长久。
                                  _________    一禅心灵庙语


五子棋

五子棋起源于中国,是全国智力运动会竞技项目之一,是一种两人对弈的纯策略型棋类游戏。双方分别使用黑白两色的棋子,下在棋盘直线与横线的交叉点上,先形成五子连珠者获胜。

五子棋容易上手,老少皆宜,而且趣味横生,引人入胜。它不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。


而我们做成后的样子是如下: 显示

在这里插入图片描述


创建项目的注意事项

  • 首先我们要明白一点就是不存在没有完完全全BUG的项目,就像人无完人一样 我们只能不断地对项目进行优化,减少BUG 的出现,但是我们好像并不能完全的消除所有的BUG
  • 而消除bug 的最好的方式就是运行测试+调试
  • 而我们在运行测试+调试 的时候,需要我们控制一定的量 ,我们需要把握住这个量 ,这一点是十分重要的,这样有助于我们快速的发现问题,也就是bug 的所在,从而提高我们的效率,减少我们的bug 的出现
  • 具体的方法,我个人有以下建议:
  1. 首先我们需要对项目进行合理的分类,那个类,那个文件实现什么样的功能: 比如:一个类是用于定义什么类型,方法的 ,另一个类是用于什么头main 的,再另外一个类是用于对于什么功能上的实现的 ,合理的分类,可以提高我们项目的可读性,让我们自身不会因为自己随着代码量的增加,对应功能上的增加而导致我们越敲越乱,越写越蒙
  2. 对于量上我们可以,每实现了两三个 功能就运行测试看看,是否存在错误,如果存在出现了错误,我们可以在一定的量(范围内),快速的找出哪里出现了问题,从而对它进行调试 ,解决问题,而不是,把项目整体写完了或者是已经实现了好几十个功能,才开始运行测试项目,结果一运行,bug,警告 冒出一大坨,我们先不说,让不让人,抓头发,就是找出问题,恐怕都需要不时间上的浪费吧
  3. 对于代码上的注释,没事多写明白一点,或许有一天,你会感想曾经,那个写了注释的自己或同事
  4. 对于bug 不要害怕,一点一点的调试看看,找出问题的所在,慢慢来,要有耐心,要明白一点现在bug 写的多,以后bug 跟你说拜拜,现在bug ,不解决,bug 天天对你说 明天见

五子棋实现原理解剖

我们使用分布式文件系统,编写该项目

我们这款五子棋游戏是,单机,人与人之间的对战的。角色分为用户1,用户2两位

  • 游戏菜单显示,两种情况,是开始游戏,还是退出游戏
  • 我们定义二维数组 用于五子棋的显示和存放五子棋的信息。显示情况如下:
    • 没有被下过的位置,符号 . 表示
    • 被用户1下过的位置,符号 表示
    • 被用户2下过的位置,符号 表示
  • 下棋方式是,通过输入坐标的形式,下棋
  • 棋盘结果有四种情况分别是:
    • 棋盘未满,未分胜负,继续下棋
    • 棋盘未满,分胜负,用户1 赢了
    • 棋盘未满,分胜负,用户2 赢了
    • 棋盘已满,未分胜负,平局

功能上简单细节构思

显示打印数组中以 1 开始,显示行号,以及列号

下棋中,所下坐标位置,不可超出棋盘大小,不可下在已经被下过的位置,去重,每下一步,都需要打印棋盘

每下一步棋,都需要判断,下的这一步是否,分出胜负,而不是下了好几步,才判断结果,


定义相关的变量

这里我们的棋盘的行列,用户1, 用户2,以及棋盘的结果的标识 使用 定义,方便修改,以及后期的维护

#define ROW 15    // 棋盘行数
#define COL 15    // 棋盘列数


#define PLAYER1 1     // 定义标识用户 1,
#define PLAYER2 2     // 定义标识用户 2



// 棋局中的中情况的定义
#define NEXT 0        // 表示没有结果,继续下棋
#define DRAE 3        // 表示棋盘下满了,平局结束

进入游戏的选择

我们把游戏的功能封装写在一个方法中Game() 用于 main 函数调用使用, 使用循环,根据实际情况,我们玩完了一把游戏,可能还会再来一把,所以我们使用循环——> 在循环里头——>再使用分支条件 switch 选择对应的功能, 在循环中定义一个数值,作为循环条件,方便我们更新循环条件,从而达到跳出循环,退出游戏的操作


int main()
{

	int quit = 0;     // 定义一个标识,用于循环条件的退出
	int select = 0;   // 对应功能上的选择

	while (!quit)
	{
		menc();
		printf("请输入你的选择: > ");
		scanf("%d", &select);      // 选择游戏模式

		switch (select)
		{
		case 1:
			Game();     // 进去游戏
			break;
		case 0:
			quit = 1;   // 通过改变循环条件,跳出循环,结束游戏
			printf("ByeBye!ln\n");
			break;
		default:        // 选择错误重新选择
			printf("Enter Error , Try Again!!! \n");
			break;
		}
		
	}

	return 0;
}

打印菜单的功能的实现

void menc()   // 游戏菜单
{
	printf("#########################\n");
	printf("### 1.paly     0.Exot ###\n");
	printf("##### Please Select #####\n");
	printf("#########################\n");

}

游戏函数 Game( ) 的构建

  1. 首先我们需要创建一个二维数组作为棋盘使用,并使用函数 memset 初始化二维数组(棋盘),同时定义一个变量,用于保存棋盘是否继续,如int result = NEXT ,其中的NEXT就是我们定义的标记:未分胜负,棋盘继续的标识
  2. 游戏是只有在分出胜负,才会结束,所以需要让游戏不要中途停止,所以写成循环的方式,进行游戏。
  3. 定义一个函数用于打印棋盘,如:showBoard(board, ROW, COL) 用于打印棋盘,每下一步都需要打印棋盘,传的参数为(数组,数组的行,数组的列)
  4. 接着定义一个下棋的函数用于下棋,如:playerMove(board, ROW, COL, PLAYER1) ,传的参数是(数组,数组的列,数组的行,谁下的(用户标识符号))
  5. 定义一个判断每下一棋,判断是否出胜负的函数如:result = isOver(board, ROW, COL),并返回结果(用户1赢,用户2赢,平局,继续),根据返回结果,如果返回值,不是继续,说明分出结果了,跳出循环,结束游戏,
  6. 退出循环后,再根据返回判断胜负的返回值,判断是谁赢了,还是平局,使用switch(result) 分支语句

逻辑思路

打印棋盘(showBoard( ))——> 用户1下棋(playerMove( ))——>判断胜负结果( isOver( )),(结果上未分胜负)——>打印棋盘(showBoard( ))——>用户2下棋(playerMove( ))——> 判断胜负结果( isOver( )),(结果上未分胜负)——>打印棋盘(showBoard( ))——> 再用户1下棋(playerMove( )),一直这样循环直到分出胜负( isOver( ))

在这里插入图片描述


void Game()
{
	int board[ROW][COL];                 // 使用二维数组,定义棋盘
	memset(board, 0, sizeof(board));     // 初始化二维数组
	int result = NEXT;                   // 游戏继续

	do {
		showBoard(board, ROW, COL);               // 打印棋盘
		playerMove(board, ROW, COL, PLAYER1);      // 用户1 下棋
		result = isOver(board, ROW, COL);      // 判断下了这一手,是否有结果,结果返回

		if (NEXT != result)   // 根据判断后的返回值,判断是否出了结果,是否还需要继续,NEXT 表示继续
		{
			break;
		}
		showBoard(board, ROW, COL);               // 打印棋盘
		playerMove(board, ROW, COL, PLAYER2);      // 用户2 下棋
	    result = isOver(board, ROW, COL);      // 判断下了这一手,是否有结果,结果返回

		if (NEXT != result)    // 根据判断后的返回值,判断是否出了结果,是否还需要继续, NEXT 表示继续
		{
			break;
		}

		

	} while (1);

	 
	// 跳出循环,根据返回值,判断该局的,结果是,谁赢,谁输,还是平局
	switch (result)
	{
	case PLAYER1:
		showBoard(board, ROW, COL);               // 打印棋盘
		printf("恭喜用户1,你赢了\n");
		break;
	case PLAYER2:
		showBoard(board, ROW, COL);               // 打印棋盘
		printf("恭喜用户2,你赢了\n");
		break;
	case DRAE:
		showBoard(board, ROW, COL);               // 打印棋盘
		printf("平分秋色,平局\n");
		break;
	default:           // 不可能会执行到的,这里设置是为了以防万一
		break;
	}
	
}

打印棋盘showBoard() 函数

  1. 首先我们需要清屏,每打印一个新的棋盘,清屏一下,这样体验效果更好,注意我们显示的无论是行号还是列好都是从 1 开始的,所以在打印的过程中需要 +1
  2. 首先打印两个空格,为打印棋行号,空出位置,更加美观,再打印列号
  3. 再使用两层循环打印二维数组,显示棋盘,第一层循环打印行号
  4. 两层循环遍历打印二维数组(显示棋盘),同时判断没有下过的位置以符号==.== 显示,用户1:下过的使用 显示,用户2:下过的使用 显示:

// 打印二维数组
void showBoard(const int board[ROW][COL], const int row, const int col)
{
//	printf("\e[1;1H\e[2J");  // 清屏
	system("cls");
	int i = 0;
	printf("  ");   // 两个空格
	for (; i < row; i++)    // 打印行号
	{
		printf("%3d", i+1);   // 预留三个位置
	}
	printf("\n");

	for (i = 0; i < row; i++)
	{
		int j = 0;
		printf("%2d ",i + 1);  // 预留两个位置
		for (j; j < col; j++)
		{
			if (0 == board[i][j])    // 没有下过的位置打印 为 .
			{
				printf(" . ");
			} 
			else if (PLAYER1 == board[i][j]) {  // 用户1 的显示符号●
				printf("● ");
			}
			else                          // 不等于,则是用户2 的显示符号 ○
			{
				printf("○ ");                 
			}
		}
		printf("\n");

	}

}

下棋playerMove( )函数

  1. 使用 static 修饰该函数,封装该函数,让函数只能在该文件内使用,提高代码的可维护性
  2. 定义两个全局变量,用于保存,赋值输入的坐标位置,
  3. 判断输入的坐标是否合理:
    • 是否超出棋盘的大小,下的位置是否被人下过。
    • 注意我们输入的坐标是从 1 下标开始的,而数组是从 0 下标开始的,所以在赋值的过程中需要 -1
  4. 写成循环,因为有可能输入的坐标不合理,需要重新输入,合理时,赋值坐标到数组中,并退出循环,注意赋值到数组中的值,是该用户所下的,标识数值。在宏中就定义好的
  5. #define PLAYER1 1 // 定义标识用户 1
    #define PLAYER2 2 // 定义标识用户 2
// 下棋
static void playerMove(int board[ROW][COL], const int row, const int col, const int who)
{
	while (1)
	{
		printf("player[%d] pleach Enter Your Pos#> ", who);  // 提示打印用户谁的输入
		scanf("%d %d", &x, &y);       // 输入坐标


		// 输入的坐标超出了棋盘,不合法,重新输入
		if (x < 1 || x > row || y < 1 || y > col)
		{
			printf("超过棋盘了,请重新输入\n");
			continue;    // 跳过本次循环,重新输入
		}

		// 输入的坐标位置,已经被占用了,不合法,重新输入
		if (0 != board[x-1][y-1])     
		{
			printf("pos IsOccupied!\n");
			continue;   // 跳过本次循环,重新输入
		}


		// 运行到这,说明该坐标没有问题,可以下入到棋盘中去了
		board[x - 1][y - 1] = who;
		break;    // 跳出循环

	}

}

判断胜负isOver( )函数

  1. 使用 static 修饰该函数,封装该函数,让函数只能在该文件内使用,提高代码的可维护性

  2. 定义一个枚举结构用于表示各个方位的数值的标识,如typedef enum Dir

  3. 定义一个函数chessCount(board, row, col, LEFT) ,用于计算二维数组中各个方位的上相同的连续出现的数值,返回计算得到的数值,因为在该函数中并没有计算到包含到,本身所下的个数,所以需要额外加上 +1

  4. 判断返回的连续出现的数值,是否存在 >=5 的个数,有则存在,五子连珠的情况说明有人赢了,再根据所走这步的,用户是谁,判断是谁,赢了

  5. 如果没有五子连珠,则再循环遍历二位数组,是否全部下完了,但凡存在没下的,下完了,则表示棋盘未满,未分出胜负,返回继续下棋,返回值为return NEXT

  6. 以上4,5这两种情况都没有出现的话,棋盘满了,未分出胜负,平局,返回值为 return DRAE

枚举类型:表示方位

typedef enum Dir  // 枚举 坐标上的方向,注意,枚举以逗号分割开来
{
	LEFT,       // 左边
	RIGHT,      // 右边
	UP,         // 上边
	DOWN,       // 下边
	LEFT_UP,    // 左上边
	LEFT_DOWN,  // 左下边
	RIGHT_UP,   // 右上边
	RIGHT_DOWN  // 右下边
	// 注意 枚举中的最后一个属性,不要加逗号分隔开,不然会报错的
}Dir;

// 走一步,判断结果
static int isOver(const int board[ROW][COL], const int row, const int col)
{
	// 从四个位置上判断,可能五子连珠的,可能性,当连续的相同的字符,数量个数为 5 时,表示有一方赢了

	// 在此基础上都需要加上 1 ,因为本身的位置上的,没有包含计算上,是需要计算上的
	// 左右横方向上的个数
	int count1 = chessCount(board, row, col, LEFT) + chessCount(board, row, col, RIGHT) + 1;
	// 上下纵方向上的个数
	int count2 = chessCount(board, row, col, UP) + chessCount(board, row, col, DOWN) + 1;
	// 左斜上方向上的个数
	int count3 = chessCount(board, row, col, LEFT_DOWN) + chessCount(board, row, col, RIGHT_UP) + 1;
	// 右斜下方向上的个数
	int count4 = chessCount(board, row, col, LEFT_UP) + chessCount(board, row, col, RIGHT_DOWN) + 1;


	// 只要在任意位置上,个数上 >= 5 就,实现了五子连珠,就有获胜了
	if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5)
	{
		if (board[x - 1][y - 1] == PLAYER1)
		{
			return PLAYER1;   // 表示用户1 赢了
		}
		else
		{
			return PLAYER2;   //否则就是 表示用户2 赢了
		}
	}


	// 循环遍历二维数组(棋盘),判断棋盘是否存在满了,如果有一个棋位置,还可以下,就表示还可以继续下棋,
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			if (board[i][j] == 0)
			{
				return NEXT;   // 继续,棋盘没有满
			}
		}
	}

	return DRAE;        // 走到这表示棋盘满了,平局

}

计算坐标周围连续的个数chessCount( )函数

在这里插入图片描述


根据所下的位置判断,是否存在五子连珠 的情况:一共存在四种情况分别是

  • 横方向上的 五子连珠

在这里插入图片描述

  • 纵方向上的五子连珠

在这里插入图片描述

  • 左斜向下的五子连珠

在这里插入图片描述

  • 右斜上的五子连珠

在这里插入图片描述


注意 :编程中的图形界面上的坐标是与,数学上的坐标是相反的,数学上的,横为 X轴,纵为 Y轴 ,而编程中的是横为 Y轴,纵为 X 轴 ,如下图所示:

在这里插入图片描述

根据所传参数中的方位,定义多条分支选择switch() ,作出相应的坐标上的移动,我们需要保留原来的坐标位置用于判断,所以我们需要拷贝复制一份,坐标用于移动,防止丢失原来的坐标位置,因为我们需要计算的是连续的,所以需要写在循环中,

方位上的移动坐标

左边 :y–;

右边:y++;

上边:x++;

下边:x–;

左下边:y–;x–;

左上边:x++;y–;

右上边:y++;x++;

右下边:y++;x–;


  1. 每移动一个坐标位置,都需要判断该坐标是否,越界了,是否超出了棋盘的范围,超出了,不用计算了,跳出循环
  2. 在确定移动坐标合理时,再判断该移动的坐标位置上的数值,是否与你所下的位置上的坐标上的数值相等,相等说明连续,计数,不相等,说明不连续,不计数,退出循环
  3. 退出循环后,返回所计数的结果
  4. 最后,因为该函数计数时,是没有计算到,包含到,所下位置的本身个数,所以需要额外 + 1

// 计算下的点位置上的,4个方向上的连续字符的 个数,
// 注意编程上的图形界面的坐标是,与数学上的坐标 x,y 是相反的,横坐标为 y, 纵坐标为 x 的
int chessCount(const int board[ROW][COL], const int row, const int col, Dir d)
{
	int count = 0;
	int _x = x-1;
	int _y = y-1;   // 拷贝一份坐标,用于移动,防止改变原来的,坐标,
	                // 注意是在数组上的实际坐标,不是你输入的,数组从零开始

	while (1)
	{
		switch (d)
		{
		case LEFT:        // 左边
			_y--;
			break;
		case UP:          // 上边
			_x++;
			break;
		case DOWN:        // 下边
			_x--;
			break;
		case LEFT_DOWN:   // 左下
			_x--;
			_y--;
			break;
		case LEFT_UP:     // 左上
			_x++;
			_y--;
			break;
		case RIGHT:       // 右边
			_y++;
			break;
		case RIGHT_DOWN:  // 右下
			_x--;
			_y++;
			break;
		case RIGHT_UP:    // 右上
			_x++;
			_y++;
			break;
		default:
			break;
		}


		// 坐标越界了,跳出循环
		if (_x < 0 || _x > row - 1 || _y < 0 || -y > col - 1)
		{
			break;
		}

		//if (board[_x][_y] != board[x - 1][y - 1])
		//{
		//	break;      // 表示数组上的数值也就是棋盘上的点,不连续了,不用加加了,跳出循环
		//}

		if (board[_x][_y] == board[x - 1][y - 1])
		{
			count++;     // 说明数组上的数值也就是棋盘上的点,连续,加加计数
		} 
		else  // 否则表示不相等,不连续,跳出循环
		{
			break; // 表示数组上的数值也就是棋盘上的点,不连续了,不用加加了,跳出循环
		}


	}

	return count;    // 跳出循环,返回在连续的个数
}

所有功能都实现了,可以运行该项目程序了,判断是否存在错误

在这里插入图片描述


五子棋完整代码实现

这里采用了分布式文件系统,其中的代码大家只需要,根据对应的文件,复制粘贴内容,就可以了,使用 VS 运行了,注意:不要缺失了,不然,可能无法运行的

game.h

用于存放 :头文件的引入,宏定义,变量,函数的声明,结构体,枚举

#pragma once
#define  _CRT_SECURE_NO_WARNINGS  1

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


#define ROW 15    // 棋盘行数
#define COL 15    // 棋盘列数


#define PLAYER1 1     // 定义标识用户 1,
#define PLAYER2 2     // 定义标识用户 2



// 棋局中的中情况的定义
#define NEXT 0        // 表示没有结果,继续下棋
#define DRAE 3        // 表示棋盘下满了,平局结束



typedef enum Dir  // 枚举 坐标上的方向,注意,枚举以逗号分割开来
{
	LEFT,       // 左边
	RIGHT,      // 右边
	UP,         // 上边
	DOWN,       // 下边
	LEFT_UP,    // 左上边
	LEFT_DOWN,  // 左下边
	RIGHT_UP,   // 右上边
	RIGHT_DOWN  // 右下边
	// 注意 枚举中的最后一个属性,不要加逗号分隔开,不然会报错的
}Dir;

extern void menc();      // 打印游戏菜单
extern void Game();      // 进入游戏
extern void playerMove(int board[ROW][COL], const int row, const int col, const int who);    // 下棋
extern int isOver(const int board[ROW][COL], const int row, const int col);        // 判断下一步后的,结果
extern int chessCount(const int board[ROW][COL], const int row, const int col, Dir d);     // 计算,连续出现相同的个数,从而判断是否有五子连珠
extern void showBoard(const int board[ROW][COL], const int row, const int col);    // 打印二维数组,棋盘


game.c

存放五子棋中对应功能实现的函数

#include "game.h"



int x = 0;   // 定义全局变量,X 坐标
int y = 0;   // 定义全局变量,y 坐标

void menc()   // 游戏菜单
{
	printf("#########################\n");
	printf("### 1.paly     0.Exot ###\n");
	printf("##### Please Select #####\n");
	printf("#########################\n");

}

void Game()
{
	int board[ROW][COL];                 // 使用二维数组,定义棋盘
	memset(board, 0, sizeof(board));     // 初始化二维数组
	int result = NEXT;                   // 游戏继续

	do {
		showBoard(board, ROW, COL);               // 打印棋盘
		playerMove(board, ROW, COL, PLAYER1);      // 用户1 下棋
		result = isOver(board, ROW, COL);      // 判断下了这一手,是否有结果,结果返回

		if (NEXT != result)   // 根据判断后的返回值,判断是否出了结果,是否还需要继续,NEXT 表示继续
		{
			break;
		}
		showBoard(board, ROW, COL);               // 打印棋盘
		playerMove(board, ROW, COL, PLAYER2);      // 用户2 下棋
	    result = isOver(board, ROW, COL);      // 判断下了这一手,是否有结果,结果返回

		if (NEXT != result)    // 根据判断后的返回值,判断是否出了结果,是否还需要继续, NEXT 表示继续
		{
			break;
		}

		

	} while (1);

	 
	// 跳出循环,根据返回值,判断该局的,结果是,谁赢,谁输,还是平局
	switch (result)
	{
	case PLAYER1:
		showBoard(board, ROW, COL);               // 打印棋盘
		printf("恭喜用户1,你赢了\n");
		break;
	case PLAYER2:
		showBoard(board, ROW, COL);               // 打印棋盘
		printf("恭喜用户2,你赢了\n");
		break;
	case DRAE:
		showBoard(board, ROW, COL);               // 打印棋盘
		printf("平分秋色,平局\n");
		break;
	default:           // 不可能会执行到的,这里设置是为了以防万一
		break;
	}
	
}



// 下棋
static void playerMove(int board[ROW][COL], const int row, const int col, const int who)
{
	while (1)
	{
		printf("player[%d] pleach Enter Your Pos#> ", who);  // 提示打印用户谁的输入
		scanf("%d %d", &x, &y);       // 输入坐标


		// 输入的坐标超出了棋盘,不合法,重新输入
		if (x < 1 || x > row || y < 1 || y > col)
		{
			printf("超过棋盘了,请重新输入\n");
			continue;    // 跳过本次循环,重新输入
		}

		// 输入的坐标位置,已经被占用了,不合法,重新输入
		if (0 != board[x-1][y-1])     
		{
			printf("pos IsOccupied!\n");
			continue;   // 跳过本次循环,重新输入
		}


		// 运行到这,说明该坐标没有问题,可以下入到棋盘中去了
		board[x - 1][y - 1] = who;
		break;    // 跳出循环

	}

}



// 走一步,判断结果
static int isOver(const int board[ROW][COL], const int row, const int col)
{
	// 从四个位置上判断,可能五子连珠的,可能性,当连续的相同的字符,数量个数为 5 时,表示有一方赢了

	// 在此基础上都需要加上 1 ,因为本身的位置上的,没有包含计算上,是需要计算上的
	// 左右横方向上的个数
	int count1 = chessCount(board, row, col, LEFT) + chessCount(board, row, col, RIGHT) + 1;
	// 上下纵方向上的个数
	int count2 = chessCount(board, row, col, UP) + chessCount(board, row, col, DOWN) + 1;
	// 左斜上方向上的个数
	int count3 = chessCount(board, row, col, LEFT_DOWN) + chessCount(board, row, col, RIGHT_UP) + 1;
	// 右斜下方向上的个数
	int count4 = chessCount(board, row, col, LEFT_UP) + chessCount(board, row, col, RIGHT_DOWN) + 1;


	// 只要在任意位置上,个数上 >= 5 就,实现了五子连珠,就有获胜了
	if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5)
	{
		if (board[x - 1][y - 1] == PLAYER1)
		{
			return PLAYER1;   // 表示用户1 赢了
		}
		else
		{
			return PLAYER2;   //否则就是 表示用户2 赢了
		}
	}


	// 循环遍历二维数组(棋盘),判断棋盘是否存在满了,如果有一个棋位置,还可以下,就表示还可以继续下棋,
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			if (board[i][j] == 0)
			{
				return NEXT;   // 继续,棋盘没有满
			}
		}
	}

	return DRAE;        // 走到这表示棋盘满了,平局

}



// 计算下的点位置上的,4个方向上的连续字符的 个数,
// 注意编程上的图形界面的坐标是,与数学上的坐标 x,y 是相反的,横坐标为 y, 纵坐标为 x 的
int chessCount(const int board[ROW][COL], const int row, const int col, Dir d)
{
	int count = 0;
	int _x = x-1;
	int _y = y-1;   // 拷贝一份坐标,用于移动,防止改变原来的,坐标,
	                // 注意是在数组上的实际坐标,不是你输入的,数组从零开始

	while (1)
	{
		switch (d)
		{
		case LEFT:        // 左边
			_y--;
			break;
		case UP:          // 上边
			_x++;
			break;
		case DOWN:        // 下边
			_x--;
			break;
		case LEFT_DOWN:   // 左下
			_x--;
			_y--;
			break;
		case LEFT_UP:     // 左上
			_x++;
			_y--;
			break;
		case RIGHT:       // 右边
			_y++;
			break;
		case RIGHT_DOWN:  // 右下
			_x--;
			_y++;
			break;
		case RIGHT_UP:    // 右上
			_x++;
			_y++;
			break;
		default:
			break;
		}


		// 坐标越界了,跳出循环
		if (_x < 0 || _x > row - 1 || _y < 0 || -y > col - 1)
		{
			break;
		}

		//if (board[_x][_y] != board[x - 1][y - 1])
		//{
		//	break;      // 表示数组上的数值也就是棋盘上的点,不连续了,不用加加了,跳出循环
		//}

		if (board[_x][_y] == board[x - 1][y - 1])
		{
			count++;     // 说明数组上的数值也就是棋盘上的点,连续,加加计数
		} 
		else  // 否则表示不相等,不连续,跳出循环
		{
			break; // 表示数组上的数值也就是棋盘上的点,不连续了,不用加加了,跳出循环
		}

		

	}

	return count;    // 跳出循环,返回在连续的个数
}




// 打印二维数组
void showBoard(const int board[ROW][COL], const int row, const int col)
{
//	printf("\e[1;1H\e[2J");  // 清屏
	system("cls");
	int i = 0;
	printf("  ");   // 两个空格
	for (; i < row; i++)    // 打印行号
	{
		printf("%3d", i+1);   // 预留三个位置
	}
	printf("\n");

	for (i = 0; i < row; i++)
	{
		int j = 0;
		printf("%2d ",i + 1);  // 预留两个位置
		for (j; j < col; j++)
		{
			if (0 == board[i][j])    // 没有下过的位置打印 为 .
			{
				printf(" . ");
			} 
			else if (PLAYER1 == board[i][j]) {  // 用户1 的显示符号●
				printf("● ");
			}
			else                          // 不等于,则是用户2 的显示符号 ○
			{
				printf("○ ");                 
			}
		}
		printf("\n");

	}

}


test.c

main 函数的所在文件,用于测试五子棋,是否存在错误,因为有关代码封装的比较好,所以在该main 函数中代码量并不多。

// #define  _CRT_SECURE_NO_WARNINGS  1

#include"game.h"


int main()
{

	int quit = 0;     // 定义一个标识,用于循环条件的退出
	int select = 0;   // 对应功能上的选择

	while (!quit)
	{
		menc();
		printf("请输入你的选择: > ");
		scanf("%d", &select);      // 选择游戏模式

		switch (select)
		{
		case 1:
			Game();     // 进去游戏
			break;
		case 0:
			quit = 1;   // 通过改变循环条件,跳出循环,结束游戏
			printf("ByeBye!ln\n");
			break;
		default:        // 选择错误重新选择
			printf("Enter Error , Try Again!!! \n");
			break;
		}
		
	}

	return 0;
}

这便是五子棋实现的所有代码,运行看看

在这里插入图片描述


最后:

限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值