在本篇文章中,我们将通过实现一个小游戏,来带领大家一起实操C语言程序设计的前3大步骤:

  1. 定义目标
  2. 设计程序
  3. 编写代码

游戏简介:

21点又名黑杰克(Blackjack),起源于法国,已流传到世界各地,有着悠久的历史。在世界各地的赌场中都可以看到二十一点,随着互联网的发展,二十一点开始走向网络时代。该游戏使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。

设计思想:

第一步:定义程序的目标

我们打算实现一个21点扑克小游戏。

基本框架

游戏初始化:

进行发牌

  • 电脑2张牌:1张明牌 1张暗牌
  • 玩家2张牌:2张明牌
游戏开始:

回合制——玩家与电脑轮流进行操作(第一次由玩家选择)

回合过程中:

可以选择继续拿牌或者停止拿牌

游戏结束:

判断输赢

若回合过程中,手上牌点数之和,大于24,即爆掉,立即失败。

若双方皆停止拿牌,则将双方手上牌点数之和进行比较,较大者赢得比赛。若一样大,则平局。

第二步:设计程序

我们这次依然遵循高内聚、低耦合的设计原理,多使用函数进行封装。

为遵循模块化编程,我们将代码分为了3个部分:

  1. game.h-----头文件模块, 用来放置函数声明与包含头文件
  2. game.c-----实现模块,用来实现游戏的所有功能
  3. tect.c---------测试模块,用来测试游戏是否可以正常运转

第三步:编写代码

game.h-----头文件模块, 用来放置函数声明与包含头文件

#pragma once

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <time.h>//为库函数 time() 提供原型
#include <stdlib.h>//为库函数 srand() 提供原先
#include <malloc.h>
#include <assert.h>

enum
{
	EXIT,
	PLAY
};

enum
{
	STAND,
	HIT
};

//游戏菜单
void Menu(void);

//发1张牌
int* Deal(int* p, int num);

//游戏主体
int Game(void);

//游戏初始发牌
int Action(void);

//电脑回合
void Computer_bout(int* me, int my_num, int* you, int your_num);

//玩家回合
void Player_bout(int* p, int num);

//打印牌
void Show(int* p, int num);

//计算手上的牌有几点
int Calc(int* p, int num);

//判断是否爆点(超过24点)
int Judge_bust(int* p, int num);

//判断谁是赢家
void Judge_winer(int* p, int num_p, int* p_2, int num_p2, int flag);

game.c-----实现模块,用来实现游戏的所有功能

#include "game.h"

int* computer = NULL;
int* player = NULL;
static int i = 0;
static int j = 0;


void Menu(void)
{
	printf("\n*******************\n");
	printf("*******1.Paly******\n");
	printf("*******0.Exit******\n");
	printf("*******************\n\n");
}

int* Deal(int* p, int num)
{
	assert(p);

	int* tem = NULL;

	//增加一张牌的空间
	tem = realloc(p, sizeof(int) * ++num);
	if (tem == NULL)
	{
		perror("Deal_realloc");
	}
	p = tem;

	//在新开辟的空间中,放新牌
	//
	//rand() % 13 生成 0~12 的数
	//rand() % 13  + 1 生成 1~13 的数
	*(p + num - 1) = rand() % 13 + 1;

	return p;
}

int Calc(int* p, int num)
{
	assert(p);

	int sum = 0;
	int k = 0;

	for (k = 0; k < num; k++)
	{
		sum += *(p + k);
	}

	return sum;
}

int Action(void)
{

	//游戏开始
	//电脑2张牌:1张明牌 1张暗牌
	//玩家2张牌:2张明牌
	
	//电脑数据开辟空间
	computer = calloc(2, sizeof(int));
	if (computer == NULL)
	{
		perror("calloc_computer");
		return 1;
	}

	//玩家数据开辟空间
	player = calloc(2, sizeof(int));
	if (player == NULL)
	{
		perror("calloc_player");
		return 1;
	}

	//发牌 -> 电脑
	*computer = rand() % 13 + 1;
	*(computer + 1) = rand() % 13 + 1;
	i = 2;

	//发牌 -> 玩家
	*player = rand() % 13 + 1;
	*(player + 1) = rand() % 13 + 1;
	j = 2;

	return 0;
}

//bust -> 返回1
//no bust -> 返回0
int Judge_bust(int* p, int num)
{
	assert(p);
	int k = 0;
	int sum = 0;

	for (k = 0; k < num; k++)
	{
		sum += *(p + k);
		if (sum > 24)
		{
			return 1;
		}
	}
	return 0;
}
void Computer_bout(int* me, int my_num, int* you, int your_num)
{
	assert(me && you);

	int sum = 0;

	printf("------电脑回合------\n");

	//计算手上的牌有几点
	sum = Calc(me, i);

	//小于17点 or 小于玩家手上的牌数 -> 继续拿牌 
	if (sum < 17 || sum < Calc(you, your_num))
	{
		printf("电脑选择拿牌\n");
		printf("正在发牌......\n");
		computer = Deal(me, i);
		i++;
		printf("电脑的牌为:");
		//第一张牌为暗牌,不展示
		printf("* ");
		Show(computer + 1, i - 1);

	}
	else
	{
		printf("电脑选择停止拿牌\n");
	}
}

void Player_bout(int* p, int num)
{
	assert(p);

	printf("正在发牌......\n");
	printf("..............\n");
	printf("..............\n");
	printf("..............\n");
	player = Deal(p, num);
	j++;
	printf("您的牌为:");
	Show(player, j);
	printf("\n");
}

void Show(int* p, int num)
{
	assert(p);

	int k = 0;

	for (k = 0; k < num; k++)
	{
		printf("%d ", *(p + k));
	}
}

//前者大  ->  返回值大于0
//后者大  ->  返回值小于0
//一样大  ->  返回值等于0
void Judge_winer(int* p, int num_p, int* p_2, int num_p2, int flag)
{
	assert(p && p_2);

	int sum_p = 0;
	int sum_p2 = 0;
	int k = 0;
	int winer = 0;

	//电脑爆掉
	if (flag == 1 )
	{
		printf("\n恭喜您,赢得了本局比赛!\n");
	}
	//玩家爆掉
	else if (flag == -1)
	{
		printf("\n很遗憾,您输掉了本局比赛\n");
	}
	//没有人爆掉
	//进入比大小环节
	else
	{
		for (k = 0; k < num_p; k++)
		{
			sum_p += *(p + k);
		}
		for (k = 0; k < num_p2; k++)
		{
			sum_p2 += *(p_2 + k);
		}

		winer = sum_p - sum_p2;

		if (winer > 0)
		{
			printf("很遗憾,您输掉了本局比赛\n");

		}
		else if (winer < 0)
		{
			printf("恭喜您,赢得了本局比赛!\n");

		}
		else
		{
			printf("平局\n");

		}
	}
	printf("您的点数为:%d\n", Calc(player, j));
	printf("电脑的点数为:%d\n", Calc(computer, i));
}

int Game(void)
{

	int input = 0;
	int flag = 0;

	//初始发牌
	printf("\n正在发牌......\n");
	printf("..............\n");
	printf("..............\n");
	printf("..............\n\n");
	Action();

	int sum_computer = 0;
	int sum_player = 0;

	printf("电脑的初始牌为:* %d\n", *(computer + 1));
	printf("您的初始牌为: %d %d\n", *player, *(player + 1));

	do
	{
		//玩家爆掉 -> -1
		//电脑爆掉 -> 1
		if (flag == -1 || flag == 1)
		{
			break;
		}

		printf("\n———是否再次发牌?———\n");
		printf("******** 1.Hit   *********\n");
		printf("******** 0.Stand *********\n");
		printf("—————————————\n\n");
		scanf("%d", &input);

		switch (input)
		{
		//发牌
		case HIT:
			//玩家回合
			Player_bout(player, j);

			//判断是否爆掉
			if (Judge_bust(player, j) != 0)
			{
				flag = -1;
				break;
			}
			//电脑回合
			Computer_bout(computer, i, player, j);
			//判断是否爆掉
			if (Judge_bust(computer, i) != 0)
			{
				flag = 1;
			}
			break;
		case STAND:
			//电脑回合
			Computer_bout(computer, i, player, j);
			//判断是否爆掉
			if (Judge_bust(computer, i) != 0)
			{
				flag = 1;
			}
			break;
		default:
			printf("输入错误,请重新输入:");
			break;
		}

	} while (input);

	//判断输赢
	Judge_winer(computer, i, player, j, flag);

	//释放calloc开辟的空间
	free(computer);
	free(player);
	computer = NULL;
	player = NULL;

	return 0;
}

tect.c---------测试模块,用来测试游戏是否可以正常运转

#include "game.h"

int main()
{
	int input = 0;
	srand((unsigned int)time(0));

	do
	{
		Menu();
		scanf("%d", &input);

		switch (input)
		{
		case PLAY:
			Game();
			break;
		case EXIT:
			printf("退出成功\n");
			break;
		default:
			printf("输入错误,请重新输入:\n");
			break;
		}
	} while (input);

	return 0;
}

运行结果:

蓝色框框内的数字,是玩家通过输入来对游戏进行的操作

C语言实现 || 21点(纸牌小游戏)_程序设计思想