当前位置:   article > 正文

【C语言实现】玩家互战五子棋(具体步骤和代码)_五子棋c语言代码

五子棋c语言代码


前言

初学C语言,了解基本语法后,可以用来练练手。

一、问题描述

用C语言实现玩家对战的五子棋。

二、基本流程

在具体写代码之前,先来确定要实现的功能和实现流程。

  1. 创建菜单界面并选择开始或者退出游戏——菜单函数。
  2. 若选择开始则打印棋盘——打印棋盘的函数。
  3. 玩家1,玩家2,分别开始落子——落子函数。
  4. 每当玩家落子就需要判断输赢——判断是否结束的函数。
  5. 若结束则再次打印棋盘,并输出结果。
  6. 否则返回第二步开始循环。

三、步骤

为了让代码和逻辑更清晰,方便修改,调试。我们采用多文件协作,可创建三个文件,gobang.h用来存放头文件,函数以及宏定义的声明;gobang.c用于存放函数的定义;gobang_test.c用来测试程序。分别在gobang.c和gobang_test.c中引入头文件gobang.h即可。

1.构建程序主体框架以及菜单的实现

此步骤放在gobang_test.c中,是程序的开始。
包括菜单的实现,以及使用一个do while循环控制是否退出游戏,其中用switch语句实现用户的选择。

#include"gobang.h"

//游戏菜单
void Menu()
{
	printf("****************************************\n");
	printf("****          1.玩家PK              ****\n");
	printf("****          0.退出                ****\n");
	printf("****************************************\n");
}

int main()
{
	int choice;
	do
	{
		Menu();
		printf("请选择:>");
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:
			PlayersGame();
			break;
		case 0:
			break;
		default:
			printf("输入错误,请重新选择:>");
			break;
		}
	} while (choice);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

2.良好的宏定义增强代码可读性

宏定义可以让代码的可读性更好,也可以让我们写代码时减少出错。

#define ROW 20        //数组行数,可以按照需求调整
#define COL 20        //数组列数,可以按照需求调整
#define PLAYER1 1     //玩家1编号,默认棋盘数据是0,玩家1落子,该位置被改成1
#define PLAYER2 2     //玩家2编号,默认棋盘数据是0,玩家2落子,该位置被改成2

//落子之后的四种情况
#define NEXT 0        //游戏继续
#define PLAYER1_WIN 1 //玩家1赢了
#define PLAYER2_WIN 2 //玩家2赢了
#define DRAW 3        //平局

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这些定义后面都会用到。

3.构建游戏入口PlayersGame()函数

这是主要的五子棋框架,将会调用具体函数来完成。
可以将需要的函数先写出来,再具体去实现。
这里需要落一次子,就判断一次。

//玩家对战
void PlayersGame()
{
	int board[ROW][COL];//创建一个二维数组作为棋盘
	memset(board, 0, sizeof(board));//将数组每个元素赋值为零	
	int row = ROW;
	int	col = COL;
	int ret = NEXT;//获取每落一个子的结果
	while (1)
	{
		ShowBoard(board, row, col);
		PlayerMove(board, row, col, PLAYER1);
		ret = IsOver(board, row, col);    //判断是否结束
		//如果不是继续就退出
		if (ret != NEXT)
			break;
		//玩家2
		ShowBoard(board, row, col);
		PlayerMove(board, row, col, PLAYER2);
		ret = IsOver(board, row, col);    //判断是否结束
		//如果不是继续就退出
		if (ret != NEXT)
			break;

	}
	ShowBoard(board, row, col);
	switch (ret)
	{
	case PLAYER1_WIN:
		printf("恭喜玩家1获胜\n");
		break;
	case PLAYER2_WIN:
		printf("恭喜玩家1获胜\n");
		break;
	case DRAW:
		printf("平局,再战一次?\n");
		break;
	default:
		break;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

4.实现打印棋盘函数

为了更加真实的模拟棋盘,我们可以选取一些特殊符号。
默认符号比较丑陋,我们需要使用美化后的符号,下面链接里面可找到所需的黑白棋,复制粘贴即可。
特殊符号大全.

打印的时候,要根据元素的内容分别打印对印的符号。
我这里的列和行都是以0开始。

//打印棋盘
void ShowBoard(int board[][COL], int row, int col)
{
	system("cls");
	printf("   ");
	for (int i = 0; i < col; i++)
	{

		printf("%-3d", i);//打印列号
	}
	printf("\n");
	for (int i = 0; i < row; i++)
	{
		printf("%2d", i);//打印行号
		for (int j = 0; j < col; j++)
		{
			
			if (board[i][j] == PLAYER1)
			{
				//玩家1落子
				printf(" ●");
			}
			else
			{
				if (board[i][j] == PLAYER2)
					printf(" ○"); //玩家2落子
				else
					printf(" ·"); //没有玩家落子
			}			
		}
		printf("\n");
	}
	printf("\n");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

5.实现玩家落子函数

要实现玩家落子,可以用两个整形变量来获取坐标,但是后面判断输赢函数我们也会用到输入的坐标,所以需要设置成全局变量。

//因为判定结果时需要用到玩家落子的坐标,所有设置两个全局变量方便使用
int x, y;//x是行,y是列
  • 1
  • 2

参数player是用来记录当前是哪个玩家落子。


//玩家下棋
void PlayerMove(int board[][COL], int row, int col , int player)
{
	printf("请玩家%d输入落子的坐标:>",player);
	while (1)
	{
		scanf("%d%d", &x, &y);
		if (x<0 || x>=row || y<0 || y>=col)
		{
			printf("输入坐标错误,请重新输入:>");
		}
		else
		{
			if (board[x][y] != 0)
			{
				printf("此坐标已有子,请重新输入:>");
			}
			else
			{
				board[x][y] = player;//将该点改为落子的玩家的值
				break;
			}
		}
	}
	
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

6.实现判断输赢函数

这是实现五子棋的难点。
请添加图片描述
任何落子位置都有八个方向,所以判定五子连珠,本质是判定1,5方向之和,2,6方向之和,3,7方向之和,4,8方向之和,其中任意一个出现相同的连续五个棋子,即游戏结束

为了记录这八个方向我们采用枚举来记录,增加代码的可读性

// 枚举八个方向
//左右,上下,左上,左下,右上,右下
enum Dir {
	LEFT,
	RIGHT,
	UP,
	DOWN,
	LEFT_UP,
	RIGHT_DOWN,
	RIGHT_UP,
	LEFT_DOWN
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这里就需要再创建一个用来记录相连棋子数量的函数。
参数enum dir d是传入的方向。
我们采用while循环和switch语句,用来循环笔记该方向上相同棋子的数量。
我们可以参照上图,对不同的方向,坐标做相应的加减。

//棋子计数
int ChessCount(int board[][COL], int row, int col, enum dir d)
{
	int count = 0;
	int _x = x;
	int _y = y;
	while (1)
	{
		switch (d)
		{
		case UP:
			//上方
			_x--;
			break;
		case DOWN:
			_x++;
			break;
		case LEFT:
			_y--;
			break;
		case RIGHT:
			_y++;
			break;
		case LEFT_UP:
			_x--; _y--;
			break;
		case LEFT_DOWN:
			_x++; _y--;
			break;
		case RIGHT_UP:
			_x--; _y++;
			break;
		case RIGHT_DOWN:
			_x++; _y++;
			break;
		default:
			break;
		}

		//移动坐标之后,保证是否越界
		if (x < 0 || x >= row || y < 0 || y >= col)
		{
			break;
		}
		//判断是否和原棋子相同,相同则计数
		if (board[_x][_y] == board[x][y])
		{
			count++;
		}
		else
		{
			break;
		}
	}
	return count;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

四、结果演示

这里使用了清屏函数system(“cls”)使得界面更加整洁。
在这里插入图片描述

五、具体代码

gobang.h

#define _CRT_SECURE_NO_WARNINGS 1

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


#define ROW 20        //数组行数,可以按照需求调整
#define COL 20        //数组列数,可以按照需求调整
#define PLAYER1 1     //玩家1编号,默认棋盘数据是0,玩家1落子,该位置被改成1
#define PLAYER2 2     //玩家2编号,默认棋盘数据是0,玩家2落子,该位置被改成2

//落子之后的四种情况
#define NEXT 0        //游戏继续
#define PLAYER1_WIN 1 //玩家1赢了
#define PLAYER2_WIN 2 //玩家2赢了
#define DRAW 3        //平局


//因为判定结果时需要用到玩家落子的坐标,所有设置两个全局变量方便使用
int x, y;//x是行,y是列


// 枚举八个方向
//左右,上下,左上,左下,右上,右下
enum Dir {
	LEFT,
	RIGHT,
	UP,
	DOWN,
	LEFT_UP,
	RIGHT_DOWN,
	RIGHT_UP,
	LEFT_DOWN
};


//玩家对战
void PlayersGame();

//打印棋盘
void ShowBoard(int board[][COL], int row, int col);

//玩家下棋
void PlayerMove(int board[][COL], int row, int col, int player);

//判断是否结束
int IsOver(int board[][COL], int row, int col);

//棋子计数
int ChessCount(int board[][COL], int row, int col, enum dir d);

//判断棋盘是否满
//满了返回1
int BoardIsFull(int board[][COL], int row, int col);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

gobang.c


#include"gobang.h"

//玩家对战
void PlayersGame()
{
	int board[ROW][COL];//创建一个二维数组作为棋盘
	memset(board, 0, sizeof(board));//将数组每个元素赋值为零	
	int row = ROW;
	int	col = COL;
	int ret = NEXT;//获取每落一个子的结果
	while (1)
	{
		ShowBoard(board, row, col);
		PlayerMove(board, row, col, PLAYER1);
		ret = IsOver(board, row, col);    //判断是否结束
		//如果不是继续就退出
		if (ret != NEXT)
			break;
		//玩家2
		ShowBoard(board, row, col);
		PlayerMove(board, row, col, PLAYER2);
		ret = IsOver(board, row, col);    //判断是否结束
		//如果不是继续就退出
		if (ret != NEXT)
			break;

	}
	ShowBoard(board, row, col);
	switch (ret)
	{
	case PLAYER1_WIN:
		printf("恭喜玩家1获胜\n");
		break;
	case PLAYER2_WIN:
		printf("恭喜玩家1获胜\n");
		break;
	case DRAW:
		printf("平局,再战一次?\n");
		break;
	default:
		break;
	}
}

//打印棋盘
void ShowBoard(int board[][COL], int row, int col)
{
	system("cls");
	printf("   ");
	for (int i = 0; i < col; i++)
	{

		printf("%-3d", i);//打印列号
	}
	printf("\n");
	for (int i = 0; i < row; i++)
	{
		printf("%2d", i);//打印行号
		for (int j = 0; j < col; j++)
		{
			
			if (board[i][j] == PLAYER1)
			{
				//玩家1落子
				printf(" ●");
			}
			else
			{
				if (board[i][j] == PLAYER2)
					printf(" ○"); //玩家2落子
				else
					printf(" ·"); //没有玩家落子
			}
			
		}
		printf("\n");
	}
	printf("\n");
}

//玩家下棋
void PlayerMove(int board[][COL], int row, int col , int player)
{
	printf("请玩家%d输入落子的坐标:>",player);
	while (1)
	{
		scanf("%d%d", &x, &y);
		if (x<0 || x>=row || y<0 || y>=col)
		{
			printf("输入坐标错误,请重新输入:>");
		}
		else
		{
			if (board[x][y] != 0)
			{
				printf("此坐标已有子,请重新输入:>");
			}
			else
			{
				board[x][y] = player;//将该点改为落子的玩家的值
				break;
			}
		}
	}
	
}

//判断是否结束
int IsOver(int board[][COL], int row, int col)
{
	//分别统计四条线上的棋子数量
	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_UP) + ChessCount(board, row, col, RIGHT_DOWN) + 1;
	int count4 = ChessCount(board, row, col, LEFT_DOWN) + ChessCount(board, row, col, RIGHT_UP) + 1;
	if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5)
	{
		if (board[x][y] == PLAYER1)
			return PLAYER1_WIN;
		else
			return PLAYER2_WIN;
	}
	//如果没有五子联珠,判断棋盘是否满了
	if (BoardIsFull(board, row, col))
		return DRAW;//满了就平局
	else
		return NEXT;//没满就继续

}

//棋子计数
int ChessCount(int board[][COL], int row, int col, enum dir d)
{
	int count = 0;
	int _x = x;
	int _y = y;
	while (1)
	{
		switch (d)
		{
		case UP:
			//上方
			_x--;
			break;
		case DOWN:
			_x++;
			break;
		case LEFT:
			_y--;
			break;
		case RIGHT:
			_y++;
			break;
		case LEFT_UP:
			_x--; _y--;
			break;
		case LEFT_DOWN:
			_x++; _y--;
			break;
		case RIGHT_UP:
			_x--; _y++;
			break;
		case RIGHT_DOWN:
			_x++; _y++;
			break;
		default:
			break;
		}

		//移动坐标之后,保证是否越界
		if (x < 0 || x >= row || y < 0 || y >= col)
		{
			break;
		}
		//判断是否和原棋子相同,相同则计数
		if (board[_x][_y] == board[x][y])
		{
			count++;
		}
		else
		{
			break;
		}
	}
	return count;
}

//判断棋盘是否满
//满了返回1
int BoardIsFull(int board[][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			if (board[i][j] == 0)
				return 0;
		}
	}
	return 1;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203

gobang_test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"gobang.h"
//游戏菜单
void Menu()
{
	printf("****************************************\n");
	printf("****          1.玩家PK              ****\n");
	printf("****          0.退出                ****\n");
	printf("****************************************\n");
}

int main()
{
	int choice;
	do
	{
		Menu();
		printf("请选择:>");
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:
			PlayersGame();
			break;
		case 0:
			break;
		default:
			printf("输入错误,请重新选择:>");
			break;
		}
	} while (choice);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

总结

这里仅仅是玩家之间的对战,欢迎各位大佬实现在线对战,以及人机对战。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/233762
推荐阅读
相关标签
  

闽ICP备14008679号