在本篇文章中,我们将通过实现一个小游戏,来带领大家一起实操C语言程序设计的前3大步骤:
- 定义目标
- 设计程序
- 编写代码
游戏简介:
21点又名黑杰克(Blackjack),起源于法国,已流传到世界各地,有着悠久的历史。在世界各地的赌场中都可以看到二十一点,随着互联网的发展,二十一点开始走向网络时代。该游戏使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。
设计思想:
第一步:定义程序的目标
我们打算实现一个21点扑克小游戏。
基本框架
游戏初始化:
进行发牌
- 电脑2张牌:1张明牌 1张暗牌
- 玩家2张牌:2张明牌
游戏开始:
回合制——玩家与电脑轮流进行操作(第一次由玩家选择)
回合过程中:
可以选择继续拿牌或者停止拿牌
游戏结束:
判断输赢
若回合过程中,手上牌点数之和,大于24,即爆掉,立即失败。
若双方皆停止拿牌,则将双方手上牌点数之和进行比较,较大者赢得比赛。若一样大,则平局。
第二步:设计程序
我们这次依然遵循高内聚、低耦合的设计原理,多使用函数进行封装。
为遵循模块化编程,我们将代码分为了3个部分:
- game.h-----头文件模块, 用来放置函数声明与包含头文件
- game.c-----实现模块,用来实现游戏的所有功能
- 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;
}
运行结果:
蓝色框框内的数字,是玩家通过输入来对游戏进行的操作