[代码实例][C]Connect Four

本文介绍了一个使用C语言实现的Connect Four游戏源代码。该游戏支持两名玩家在线对战,利用TCP/IP协议进行网络通信。文章详细展示了如何通过C语言进行网络编程、游戏逻辑处理以及用户交互。

国内盛行五子棋的游戏,但国外还有一个名字叫“Connect Four”的游戏,两者的规则差不多。在用C语言实现这个游戏的时候会让程序设计的入门新手体验并并掌握一些技能。

说明文档如下:(优快云资源上传需要经过审核,故审核通过后补充这一部分)

实现代码如下:

/*
 * @File		CFour.c
 * @Author		HuoYun
 * @Date		2020-11-23
 * @Version		1.0.0
 * @Copyright	HuoYun
 */

#include <ctype.h>	// C标准库,提供库函数toupper()
#include <stdio.h>	// C标准库,提供库函数printf()和scanf()
#include <stdlib.h>	// C标准库,提供库函数malloc()和free()
#include <string.h> // C标准库,提供库函数memset()

#include <stdbool.h>    // C标准库,提供类型bool
#include <stdint.h>     // C标准库,提供类型uint16_t等

#include <arpa/inet.h>		// 提供POSIX接口以及TCP/IP接口
#include <sys/types.h>		//
#include <sys/socket.h>		//
#include <unistd.h>			//

bool IsServer = false;					// 标识当前程序是否是服务端部分
#define IPAddress_LEN_MAX	16			// “点分十进制”表示法IP地址的最大长度(包含结束字符)
char ServerAddress[IPAddress_LEN_MAX];	// 保存“点分十进制”表示法IP地址
uint16_t Port;							// 保存TCP/IP协议中占用的端口

int ServerFd;	// 服务端连接文件描述符
int ClientFd;	// 客户端连接文件描述符
int ListenFd;	// 服务端监听文件描述符

#define BUF_SIZE	4096	// TCP连接接口中缓冲区大小

#define NAME_LENGTH_MAX 16	// 设定玩家名字的最大长度

#define DEFAULT_WIDTH 7		// 游戏面板的默认宽度为7
#define DEFAULT_HEIGHT 6	// 游戏面板的默认高度为6

int Width = DEFAULT_WIDTH;		// 游戏面板的宽度是可变的,但目前为其默认值。
int Height = DEFAULT_HEIGHT;	// 游戏面板的搞度是可变的,但目前为其默认值。
char PlayerName[2][NAME_LENGTH_MAX + 1];	// 将两个游戏玩家的名字保存在一个字符数组的数组中,便于管理。
int* Board = NULL;	/* 面板是一个“二维”的数组(本质是数组的数组),形象地表示了现实中的游戏面板。
												数组中的元素还是一个数组,这个组数组表示面板的每一列。子数组的元素是一个整数,
												表示面板上每一列中的那个孔洞。如果子数组的某个元素值为0,则表示其对应的孔洞还
												没有落下圆盘;如果值为1,则表示其对应的孔洞已落下属于玩家1的圆盘;如果值为2,
												则表示其对应的孔洞已落下属于玩家2的圆盘。子数组的元素值不应该为其他的值,
												而当游戏初始化的时候,动态内存空间(数组中的元素)已经设置为0了,故可理解为游戏面板
												已被初始化为没有落下任何玩家的圆盘。
											 */

int IsPlayer2 = 0;		/* 这是一个哨兵变量,监视当前的玩家是不是玩家2。
							如果其值为0,则表示当前玩家是玩家1;如果其值为1,则表示当前玩家是玩家2。
							在代码的其他地方会依赖这个变量的值,故0和1以外的其他均为该变量的无效值。
						*/

						/*
						 * 此处定义三个宏,是设定与玩家相关的标识,在代码的多个地方的计算与玩家标识是紧密相关的。
						 */
#define PLAYER_FLAG_NULL 0
#define PLAYER_FLAG_1 1
#define PLAYER_FLAG_2 2

const char DiskSymbol[] = {
   
    '.', 'X', 'O' };

#define CURRENT_PLAYER_FLAG (PLAYER_FLAG_1 + IsPlayer2)		// 提供一个宏来获取当前玩家的标识。
#define ANOTHER_PLAYER_FLAG (PLAYER_FLAG_1 + !IsPlayer2)	// 提供一个宏来获取非当前玩家的标识。

#define CURRENT_PLAYER PlayerName[IsPlayer2]	/* 提供一个宏来获取当前玩家的名字。
													数组PlayerName中,第一个元素(也是一个数组),存储了玩家1的名字;
													第二个元素,存储了玩家2的名字。
												 */
#define ANOTHER_PLAYER PlayerName[!IsPlayer2]	// 提供一个宏来获取非当前玩家的名字。

#define QUIT 'Q'	// 当玩家输入字符'Q'或'q'时程序退出。因为程序在判断玩家输入时已将字母大写,故只判断一种情况即可。

int IsGameOver = 0;		/* 一个状态变量。如果计算得出某个玩家已胜出,则设定这个变量的值为非0,表示游戏已结束。
							否则,游戏仍然是在进行。
						 */

int HasPlayerQuit = 0; // 一个状态变量。如果某个玩家主动退出,则设定这个变量为非0。

int WinnerPlayerFlag = PLAYER_FLAG_NULL;	/* 一个状态变量。如果没有玩家胜出(平局),则为PLAYER_FLAG_NULL;
											 * 否则,其实被设定为赢家标识(PLAYER_FLAG_1 或 PLAYER_FLAG_2)。
											 */

int DiskCount = 0;		// 落下圆盘的总数

#define GetColumnIndex(columnName)	((columnName) - 'A')	// 将列名转换成列序号(从0开始),程序假定,列名最大至'Y'。

#define GetDiskFlag(columnIndex, rowIndex) (*(Board + Height * (columnIndex) + (rowIndex)))		// 通过行列序号获取孔洞落下圆盘。

/*
 * Function: SetServer
 * Description: 在这个函数中,程序设置网络连接并且等待,直到有客户端连接后才返回。
 * Arguments: null
 * Return: null
 */
void SetServer(void)
{
   
   
	struct sockaddr_in serverAddress;
	struct sockaddr_in clientAddress;
	socklen_t clientAddressLen;

	if((ListenFd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
   
   
		perror("socket");
		exit(EXIT_FAILURE);
	}

	memset(&serverAddress, 0, sizeof(serverAddress));
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
	serverAddress.sin_port = htons(Port);

	if(bind(ListenFd, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) == -1)
	{
   
   
		perror("bind");
		exit(EXIT_FAILURE);
	}

	if(listen(ListenFd, 1) == -1)
	{
   
   
		perror("listen");
		exit(EXIT_FAILURE);
	}

	if((ClientFd = accept(ListenFd, (struct sockaddr *)&clientAddress, &clientAddressLen)) == -1)
	{
   
   
		perror("connect");
		exit(EXIT_FAILURE);
	}
}

/*
 * Function: SetClient
 * Description: 在这个函数中,程序设置并且连接服务端。
 * Arguments: null
 * Return: null
 */
void SetClient(void)
{
   
   
	struct sockaddr_in serverAddress;

	if((ServerFd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
   
   
		perror("socket");
		exit(EXIT_FAILURE);
	}

	memset(&serverAddress, 0, sizeof(serverAddress));
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_port = htons(Port);
	if(inet_pton(AF_INET, ServerAddress, &serverAddress.sin_addr) != 1)
	{
   
   
		pe
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值