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

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

#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. SQL:查找被锁的表,以及锁表的SQL语句(重点推荐)

    --死锁检测 use master Select * --找到SPID exec sp_lock --根据SPID找到OBJID ) --根据OBJID找到表名 1.DatabaseName 同于你要 ...

  2. PHP安装所最到的问题-解决方案

    Although Drupals 7+ run smoothly on PHP 5.3, Drupal 6 still feels much better with PHP 5.2. Even tho ...

  3. Navicat(服务器对象) -2之MySQL 或 MariaDB 对象

    MySQL 或 MariaDB 对象 http://www.navicat.com.cn/manual/online_manual/cn/navicat/win_manual/index.html 要 ...

  4. Windows下运行python脚本报错“ImportError: No Module named ...”的解决方法

    之前遇到一个问题,在Pycharm或IPython之类的IDE上运行脚本正常,但是直接运行或cmd命令行运行的时候报了模块未能找到的错误--ImportError: No Module named . ...

  5. archlinux 内核编译笔记

    # cp linux-3.10.5.tar.gz /usr/src/linux-3.10.5.tar.gz# cd /usr/src# tar xvzf linux-3.10.5.tar.gz lin ...

  6. simulate windows touch input

    更多信息请参考页面http://social.technet.microsoft.com/wiki/contents/articles/6460.simulating-touch-input-in-w ...

  7. 【T电商2】ftp服务器搭建

    一.为什么需要ftp? 分布式环境一般都有一个专门的图片服务器存放图片.我们使用虚拟机搭建一个专门的服务器来存放图片.在此服务器上安装一个nginx来提供http服务,安装一个ftp服务器来提供图片上 ...

  8. C++中的RTTI机制解析

    RTTI RTTI概念 RTTI(Run Time Type Identification)即通过运行时类型识别,程序能够使用基类的指针或引用来检查着这些指针或引用所指的对象的实际派生类型. RTTI ...

  9. Hadoop HDFS编程 API入门系列之简单综合版本1(四)

    不多说,直接上代码. 代码 package zhouls.bigdata.myWholeHadoop.HDFS.hdfs4; import java.io.IOException; import ja ...

  10. 【kettle】window安装与配置

    1.下载kettle包,并解压http://community.pentaho.com/projects/data-integration/2.安装jdk,并配置java环境 a).打开我的电脑--属 ...