在内存中模拟出一副牌,然后模拟洗牌,发牌等动作。

流程是这样的:构建一副牌保存到一个数组中—洗牌—创建玩家—向玩家发牌–输出每个玩家的牌。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义扑克的花色
enum Suit{
heart,
spade,
diamond,
club,
joker1,
joker2
};
//一副牌的数量
#define CARD_COUNT 54
//定义扑克
typedef struct Card{
int value;//牌的点数从1开始
enum Suit suit;//花色
}Card;
//定义玩家
typedef struct Player{
char name[64];//玩家的名字
Card ** cards;//玩家分到的牌。每项是一个指针,指向原始一副牌数组中的一项,这样可以节省空间
int cardsCount;//玩家分到的牌的数量
}Player;
//分牌完成后调用的函数的类型
typedef int (*COMPARE)(Card* ,Card*);
//函数声明们
char* getCardName(const Card*);
Card** shuffle(const Card*);
void dispatchCards(Player** ,int ,const Card** );
void sort(Card**,int,COMPARE);
int compare1(Card* ,Card*);
int compare2(Card* ,Card*);
void initOnePack();
//原始一副牌所在的数组
Card pokers[CARD_COUNT];
//入口函数
int main(void)
{
//初始化一副牌
initOnePack(); //洗牌,shuffledPokers保存洗后的牌们
Card** shuffledPokers = shuffle(pokers);
//构建三个玩家
Player player1;
strcpy(player1.name,"隔壁老王");
player1.cards=NULL;
player1.cardsCount=0;
Player player2;
strcpy(player2.name,"小明");
player2.cards=NULL;
player2.cardsCount=0;
Player player3;
strcpy(player3.name,"田中龟孙");
player3.cards=NULL;
player3.cardsCount=0;
//把三放到一个数组中,以传入发牌函数中
Player* players[]={&player1,&player2,&player3};
//发牌
dispatchCards(players,sizeof(players)/sizeof(Player*),shuffledPokers);
//洗后的牌用完了,释放之
free(shuffledPokers);
int i;
//打印出每个玩家手中的牌
for(i=0;i<sizeof(players)/sizeof(Player*);i++){
//先打印玩家的名字
printf("%s\n",players[i]->name);
//需要对玩家手中的牌排序
sort(players[i]->cards,players[i]->cardsCount,compare1);
//打印玩家手中所有的牌
int j;
for(j=0;j<players[i]->cardsCount;j++){
char * name = getCardName(players[i]->cards[j]);
printf("%s ",name);
free(name);
}
//每个玩家都需要换一次行
printf("\n");
}
//释放玩家手中牌的数组
for(i=0;i<sizeof(players)/sizeof(Player*);i++){
free(players[i]->cards);
}
return 0;
}
//构造一副牌
void initOnePack(){
int i=0;
//前52张
for(;i<CARD_COUNT-2;i++){
pokers[i].value=i/4+1;
pokers[i].suit = i%4;
}
//剩下的两张:大王和小王
//joker1
pokers[i].value=i/4+1;
pokers[i].suit=joker1;
//joker2
pokers[i+1].value=i/4+2;
pokers[i+1].suit=joker2;
}
//洗牌,参数是原始的一副牌,返回洗完后的牌
Card** shuffle(const Card* pokers){
int i;
//分牌返回牌数组的内存空间
Card** retPokers = malloc(CARD_COUNT*sizeof(Card*));
//为了不改动原始的一副牌,另建一个数组,保存原始牌的指针(注意每项不是牌,而是牌的指针)
Card** pokers2 = malloc(CARD_COUNT*sizeof(Card*));
for(i=0;i<CARD_COUNT;i++){
pokers2[i] = &pokers[i];
}
//种下随机种子。种子取的是当前时间,
//所以保证了每次运行程序时,产生的随机数序列不同
srand(time(NULL));
//取得随机序号,从pokers2取出序号所指的项,把它依次加到retPokers中。
for(i=0;i<CARD_COUNT;i++){
unsigned int index = rand()%CARD_COUNT;
if(pokers2[index] != NULL){
retPokers[i] = pokers2[index];
pokers2[index]=NULL;
}else{
i--;
}
}
free(pokers2); //返回洗完后的数组
return retPokers;
}
//发牌
//players是玩家数组
//playerCount是玩家数量
//shuffledCards是洗完后的一副牌
void dispatchCards(Player** players,int playerCount,const Card** shuffledCards){
//计算每个玩家手中牌的数组的容量,如果每个玩家手中的牌不一样,
//最多就差一张,加1是为了保证数组分配的空间足够容纳分到的牌。
int numberCards = CARD_COUNT/playerCount+1;
//为每个玩家的牌数组分配空间
int i;
for(i=0;i<playerCount;i++){
Card* cards = malloc(numberCards*sizeof(Card*));
players[i]->cards = cards;
}
//轮流向每个玩家发牌
for(i=0;i<CARD_COUNT;i++){
//取当前玩家
Player *curPlayer = players[i%playerCount];
//向玩家发牌
curPlayer->cards[curPlayer->cardsCount] = shuffledCards[i];
//玩家手中实际的牌数增加
curPlayer->cardsCount++;
}
}
//排序函数
//cards是要排序的牌,每一项是牌的指针
//cardsCount是牌的数量
//compare_func是比较函数
void sort(Card** cards,int cardsCount,COMPARE compare_func){
int i;
for(i=0;i<cardsCount-1;i++){
int j;
for(j=0;j<cardsCount-i-1;j++){
if(compare_func(cards[j],cards[j+1])){
int tmp=cards[j];
cards[j]=cards[j+1];
cards[j+1]=tmp;
}
}
}
}
//比较函数,先比较点数再比较花色
int compare1(Card* a,Card* b){
if(a->value > b->value){
return 1;
}else if(a->value < b->value){
return 0;
}else{
if(a->suit > b->suit)
return 1;
else
return 0;
}
}
//比较函数,先比较点数再比较花色
int compare2(Card* a,Card* b){
if(a->value > b->value){
return 0;
}else if(a->value < b->value){
return 1;
}else{
if(a->suit > b->suit)
return 0;
else
return 1;
}
}
//获取牌的名字
//返回牌的名字字符串,调用者用完后需要free()之。
char* getCardName(const Card* card){
//存放花色名字
char suitStr[16]={0};//0=='\0'
switch (card->suit) {
case heart:
strcpy(suitStr,"红桃");
break;
case spade:
strcpy(suitStr,"黑桃");
break;
case diamond:
strcpy(suitStr,"方块");
break;
case club:
strcpy(suitStr,"梅花");
break;
}
//存放点数名字
char valueStr[16];
switch(card->value){
case 1:
strcpy(valueStr,"A");
break;
case 11:
strcpy(valueStr,"J");
break;
case 12:
strcpy(valueStr,"Q");
break;
case 13:
strcpy(valueStr,"K");
break;
case 14:
strcpy(valueStr,"小王");
break;
case 15:
strcpy(valueStr,"大王");
break;
default:
sprintf(valueStr,"%d",card->value);
break;
}
//动态分配足够的空间
char * ret = malloc(16);
//将两个名字合并到ret中
sprintf(ret,"%s%s",suitStr,valueStr);
return ret;
}

一个有趣的基于C++的模拟发牌程序的更多相关文章

  1. 模拟一个简单的基于tcp的远程关机程序(转)

    最近在学习unix网络编程,现在正在学习tcp的通信.其实,只要建立起了tcp通信,操作远端的计算机就不是什么问题了.正向telnet一样,也是基于tcp/IP协议的.所以这个实验,也算是对telne ...

  2. 一个有趣的基于Django的调试插件--django-debug-toolbar

    django-debug-toolbar 介绍 django-debug-toolbar 是一组可配置的面板,可显示有关当前请求/响应的各种调试信息,并在单击时显示有关面板内容的更多详细信息. git ...

  3. 基于UDP协议模拟的一个TCP协议传输系统

    TCP协议以可靠性出名,这其中包括三次握手建立连接,流控制和拥塞控制等技术.详细介绍如下: 1. TCP协议将需要发送的数据分割成数据块.数据块大小是通过MSS(maximum segment siz ...

  4. 一个有趣的模拟光照的shader

    一个有趣的模拟光照的shader(类似法线贴图) http://www.cnblogs.com/flytrace/p/3395911.html -----  可否用于需UI中需要加灯的模型.

  5. 【小贴士】关于transitionEnd/animate的一个有趣故事

    前言 在很久之前,我们项目有一个动画功能,功能本身很简单,便是典型的右进左出,并且带动画功能 以当时来说,虽然很简单,但是受限于框架本身的难度,就直接使用了CSS3的方式完成了功能 当时主要使用tra ...

  6. 在Android中访问内置SE和基于SE的卡模拟(一)

    2013-10-10 编写 前言 在“十问Android NFC手机上的卡模拟”文中仅仅简单的介绍了一下相关的概念,如果需要了解基于SE的卡模拟的更多细节,也就是,究竟在Android的NFC手机上, ...

  7. 基于Android的模拟点击探索

    前言 压力测试中,一般会用到自动化测试.准备写一个APP,可以记录屏幕上的点击事件,然后通过shell命令来模拟自动执行.shell指令,比较容易实现.那么,关键的一步是获取点击的坐标.对于Andro ...

  8. 一个有趣的小例子,带你入门协程模块-asyncio

    一个有趣的小例子,带你入门协程模块-asyncio 上篇文章写了关于yield from的用法,简单的了解异步模式,[https://www.cnblogs.com/c-x-a/p/10106031. ...

  9. NFC手机上基于软件的卡模拟 重大利好还是安全噩梦?(转)

    Software Card Emulation in NFC-enabled Mobile Phones: GreatAdvantage or Security Nightmare? Michael ...

随机推荐

  1. 原生js 实现购物车价格和总价 统计

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. Linux 下没有conio.h 已解决

    原文:http://blog.sina.com.cn/s/blog_6a95e00b0100zqvf.html #include <stdio.h>//#include <conio ...

  3. mysql 修改字段类型

    1.更改Float字段类型to Decimal ALTER TABLE 表名 MODIFY 字段名 decimal(10,2) not null default '0': 如: ALTER TABLE ...

  4. Crt单元

    一.调用单元例:uses crt; 二.清屏例:clrscr; 三.移动光标例:gotoxy(a,b);其中a表示列号,b表示行号 四.清行例:clreol;清除光标所在行光标上及以后的所有字符 五. ...

  5. [DFNews] What's coming in EnCase 7.08?

    论版本变化速度,AD绝对首屈一指,从FTK 4到现在的FTK 5也不过两年多时间,EnCase近期(初步预计8月初)将推出V7的新版本7.08,下面是一些新功能: Evidence Processor ...

  6. 剑指offer习题集2

    1.把数组排成最小的数 class Solution { public: static bool compare(const string& s1, const string& s2) ...

  7. 关于对inputstream流的复制

    今天因为项目需要,获取到一个inputstream后,可能要多次利用它进行read的操作.由于流读过一次就不能再读了,所以得想点办法. 而InputStream对象本身不能复制,因为它没有实现Clon ...

  8. iOS开发中的4种数据持久化方式【一、属性列表与归档解档】

    iOS中的永久存储,也就是在关机重新启动设备,或者关闭应用时,不会丢失数据.在实际开发应用时,往往需要持久存储数据的,这样用户才能在对应用进行操作后,再次启动能看到自己更改的结果与痕迹.ios开发中, ...

  9. JS settimeout 使用笔记

    无参数使用方法: setTimeout(function_name,delay_time); 基本使用方法是逗号前是函数名字,不能带有 xxxx(),不然不执行: 但是很多函数都要带参数的,以下是解决 ...

  10. Web 开发常见安全问题

    不是所有 Web 开发者都有安全的概念,甚至可能某些安全漏洞从来都没听说过.这就是这篇科普文章的存在意义,希望 Web 开发者在开发时能依此逐条检查代码中的安全问题. 注:服务器运维相关的安全注意事项 ...