C++扑克牌随机洗牌抽牌算法

  • 题目
  • 算法思想
  • 代码解析
  • 完整代码

目录

题目

4个人甲乙丙丁一起玩扑克牌,其中1-10各种花色纸牌分别为1-10,J、Q、K被记为11、12、13,大王小王都记为20.四种花色(方块、梅花、红桃、黑桃)分别被记为A、B、C、D。如红桃K表示为13C,分值13;方块5表示为5A,分值5;大王表示为20K,分值20;小王表示为20Q,分值20。
游戏过程如下:
1、洗牌:54张牌随机组合
2、4人排序:随机产生4人的拿牌顺序,拿牌顺序与出牌顺序相同。
3、分派:按拿牌顺序每人轮流拿牌,每人拿13张,最后两张留在桌面。
4、出牌:从第一个拿牌的人开始出牌(随即出牌),每一轮4人出牌,牌最大的获取当前轮次的四张牌。大小判定规则,纸牌分值大>纸牌分值小,相同指派分值,按照黑桃>红桃>梅花>方块。

算法思想

洗牌、四人排序以及随机出牌都是随机且不重复抽取。如果用随机函数直接随机生成数字然后再判定是否重复,这样算法复杂且时间复杂度高,可以逆向思考为生成一个随机排列的序号数组,然后顺序输出随机排列的序号数组。
牌面的大小判定可以先用一个循环判定数字大小,然后因为由字符的ASCII码值判定花色大小。

代码解析

  • 构建对象Player(玩家)
    Player的属性有名字、手中拥有的牌、出牌顺序、分数;
    构造函数,在玩家对象被声明的时候,就要赋予玩家名字,将其分数置为0
 Player(string name) //构造函数{p_name = name;p_score = 0;}

对象声明

//玩家
class Player
{private:string p_name;    //玩家的名字int p_card_index[13];    //牌面的序号vector<int> p_s_index;  //随机的出牌顺序int p_score;  //玩家的得分
public:Player(string name) //构造函数{p_name = name;p_score = 0;}string getName(){return p_name;};  //      查看名字void saveCard(int n,int i){p_card_index[n] = i;};       //将第n轮分到了序号为i的牌保存下来int getCard(int i);   //第i轮随机出牌。输出出牌序号int showCard(int i){return p_card_index[i];}   //第i轮分到的牌void addScore(int s){p_score += s;};   //分数增加s分int getScore(){return p_score;};    //查看此时的分数
};

C++11的标准库中有一个函数shuffle()
函数原型:

template <class RandomAccessIterator, class URNG>
void shuffle (RandomAccessIterator first, RandomAccessIterator last, URNG&& g);

函数功能:
使用随机生成器g对元素[first, last)的容器内部元素进行随机排列
函数参数:

first, last g
顺序容器迭代器的开头和结尾 随机数生成器的一个实例

card_index.push_back(i),向容器末尾添加新元素i。
seed = chrono::system_clock::now().time_since_epoch().count(),用seed来初始化生成器,避免出现重复的排列。

#include <algorithm> // std::move_backward
#include <random> // std::default_random_engine
#include <chrono> // std::chrono::system_clock//将扑克牌顺序打乱
void rand_cards(vector<int>& card_index) //洗牌
{for(int i=0; i<54; i++)card_index.push_back(i);//card_index[i]=i;unsigned seed = chrono::system_clock::now().time_since_epoch().count();shuffle(card_index.begin(),card_index.end(),default_random_engine(seed));}void rand_players(vector<int>& s_players)  //四人排序
{for(int i=0; i<4; i++)s_players.push_back(i);unsigned seed = chrono::system_clock::now().time_since_epoch().count();shuffle(s_players.begin(),s_players.end(),default_random_engine(seed));}
int Player::getCard(int i)//对象的成员函数,生成每个玩家的随机出牌顺序
{for(int i=0; i<13; i++)p_s_index.push_back(i);unsigned seed = chrono::system_clock::now().time_since_epoch().count();shuffle(p_s_index.begin(),p_s_index.end(),default_random_engine(seed));return p_card_index[p_s_index[i]];//根据生成的顺序从自己所拥有的牌中抽取
}

分牌,将打乱顺序的牌按照之间随机的四人分派顺序分配给玩家。

void deal_cards(Player* p,vector<int> s_players,vector<int> card_index)//分牌
{int t=0;  //记录轮次for(int i=0; i<52; i++){if(i%4==0&&i!=0)//每过4人就到了下一轮t++;p[s_players[i%4]].saveCard(t,card_index[i]);}}

玩家出牌并比较各自的牌大小,最大的拿分

void play_cards(Player* p) //出牌
{for(int i=0;i<13;i++){int win = Compare_cards(i,p);   //找出第i轮胜利者int score = 0;for(int j=0;j<4;j++)    //算出总分score += getValue(p[j].getCard(i));p[win].addScore(score);}
}int Compare_cards(int i,Player p[])//比较第i轮四个人谁赢
{int p_num[4];   //四个人第i轮的牌面序号for(int j=0; j<4; j++)p_num[j] = p[j].getCard(i);int maxp[4]= {1,0,0,0}; //假设最大的是第一个人int maxj=0;for(int j=1; j < 4; j++) //选出数字最大者{if(getValue(p_num[j]) > getValue(p_num[maxj]))//若比最大者大,则更改记录{ maxp[maxj] = 0;maxp[j] = 1;maxj = j;}else if(getValue(p_num[j]) == getValue(p_num[maxj]))//若相等,则加入记录maxp[j] = 1;}for(int j=0; j<4; j++) //选出字母最大者if(maxp[j]){int bigger = Bigger_pattern(p_num[j], p_num[maxj]);if(p_num[j] == bigger)maxj = j;}return maxj;
}int Bigger_pattern(int a,int b)   //a,b为花色序号,只比较花色
{string a_s,b_s;    //序号转化为牌面a_s = cards[a];b_s = cards[b];char a_ch,b_ch;//牌面转化为花色a_ch = a_s[a_s.length()-1];b_ch = b_s[b_s.length()-1];switch(a_ch)//花色为K、Q单独讨论,为A~D直接用ASCII码计算{case 'K':return a;case 'Q':if(b_ch=='K')return b;elsereturn a;case 'D':case 'C':case 'B':case 'A':return (a_ch-b_ch)?a:b;default:cout<<"pattern error"<<endl;break;}
}

完整代码

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<random>
#include<chrono>using namespace std;
//卡牌
const string cards[54] {"1A","2A","3A","4A","5A","6A","7A","8A","9A","10A","11A","12A","13A","1B","2B","3B","4B","5B","6B","7B","8B","9B","10B","11B","12B","13B","1C","2C","3C","4C","5C","6C","7C","8C","9C","10C","11C","12C","13C","1D","2D","3D","4D","5D","6D","7D","8D","9D","10D","11D","12D","13D","20K","20Q"};//玩家
class Player
{private:string p_name;//玩家的名字int p_card_index[13];//牌面的序号vector<int> p_s_index;//随机的出牌顺序int p_score;//玩家的得分
public:Player(string name) //构造函数{p_name = name;p_score = 0;};string getName(){return p_name;};//查看名字void saveCard(int n,int i){p_card_index[n] = i;};//第n轮分到了序号为i的牌int getCard(int i);//第i轮出牌序号int showCard(int i){return p_card_index[i];};//第i轮拿到的牌void addScore(int s){p_score += s;};//分数增加s分int getScore(){return p_score;};//查看此时的分数
};int getValue(int i);//将卡牌序号转化为分数
int Compare_cards(int i,Player* p_play);//比较第i轮四个人谁赢
int Bigger_pattern(int a,int b);//两个花色比较
int win_player(Player p[]);//最终胜利的人void rand_cards(vector<int>& card_index);//洗牌
void rand_players(vector<int>& s_players);//四人排序
void deal_cards(Player* p,vector<int> s_players,vector<int> card_index);//分牌
void play_cards(Player* p);//出牌
void show(Player p_play[4]);//展示结果int main()
{Player p_play[4]={Player("甲"),Player("乙"),Player("丙"),Player("丁")};//四个人玩vector<int> card_index;//54张牌vector<int> s_players;//四人分牌顺序rand_players(s_players);//四人排序rand_cards(card_index);//洗牌deal_cards(p_play,s_players,card_index);//分牌play_cards(p_play);//出牌show(p_play);//展示结果return 0;
}int getValue(int i)//将卡牌序号转化为分数
{string s = cards[i];int value = 0;for(int i = 0; i<s.length()-1; i++)value = value*10 + s[i]-'0';return value;
}int Compare_cards(int i,Player p[])//比较第i轮四个人谁赢
{int p_num[4];   //四个人第i轮的牌面序号for(int j=0; j<4; j++){p_num[j] = p[j].getCard(i);}int maxp[4]= {1,0,0,0}; //假设最大的是第一个人int maxj=0;for(int j=1; j < 4; j++) //选出数字最大者{if(getValue(p_num[j]) > getValue(p_num[maxj])){maxp[maxj] = 0;maxp[j] = 1;maxj = j;}else if(getValue(p_num[j]) == getValue(p_num[maxj]))maxp[j] = 1;}//选出字母最大者for(int j=0; j<4; j++)if(maxp[j]){int bigger = Bigger_pattern(p_num[j], p_num[maxj]);if(p_num[j] == bigger)maxj = j; }return maxj;
}int Bigger_pattern(int a,int b)   //a,b为花色序号,只比较花色
{string a_s,b_s;a_s = cards[a];b_s = cards[b];char a_ch,b_ch;a_ch = a_s[a_s.length()-1];b_ch = b_s[b_s.length()-1];switch(a_ch){case 'K':return a;case 'Q':if(b_ch=='K')return b;elsereturn a;case 'D':case 'C':case 'B':case 'A':return (a_ch-b_ch)?a:b;default:cout<<"pattern error"<<endl;break;}
}int win_player(Player p[]) //最终胜利的人
{int maxi=0,maxScore=p[0].getScore();    //假设第一个人是最终胜利者for(int i=1;i<4;i++){int score = p[i].getScore();if(score > maxScore){ maxScore = score;maxi = i;}}return maxi;
}void rand_cards(vector<int>& card_index) //洗牌
{for(int i=0; i<54; i++)card_index.push_back(i);unsigned seed = chrono::system_clock::now().time_since_epoch().count();shuffle(card_index.begin(),card_index.end(),default_random_engine(seed));
}void rand_players(vector<int>& s_players)  //四人排序
{for(int i=0; i<4; i++)s_players.push_back(i);unsigned seed = chrono::system_clock::now().time_since_epoch().count();shuffle(s_players.begin(),s_players.end(),default_random_engine(seed));
}void deal_cards(Player* p,vector<int> s_players,vector<int> card_index) //分牌
{int t=0;for(int i=0; i<52; i++){if(i%4==0&&i!=0)t++;p[s_players[i%4]].saveCard(t,card_index[i]);}
}void play_cards(Player* p) //出牌
{for(int i=0;i<13;i++){int win = Compare_cards(i,p);   //找出第i轮胜利者int score = 0;for(int j=0;j<4;j++)    //算出总分score += getValue(p[j].getCard(i));p[win].addScore(score);}
}void show(Player p[4])  //展示结果
{for(int i = 0;i<4;i++){cout<<p[i].getName();for(int j = 0;j<13;j++){cout<<cards[p[i].showCard(j)];if(j==12)cout<<endl;else cout<<" , ";}}cout<<"得分:"<<endl;for(int i =0;i<4;i++)cout<<p[i].getName()<<" "<<p[i].getScore()<<endl;cout<<"得分最多:"<<p[win_player(p)].getName();}int Player::getCard(int i)//生成随机出牌顺序
{for(int i=0; i<13; i++)p_s_index.push_back(i);unsigned seed = chrono::system_clock::now().time_since_epoch().count();shuffle(p_s_index.begin(),p_s_index.end(),default_random_engine(seed));return p_card_index[p_s_index[i]];
}

C++扑克牌随机洗牌抽牌算法相关推荐

  1. c语言扑克牌随机发三张牌,扑克牌发三张概率组合一副扑克牌52张(不含大、小王),发三张牌,一共多少种组合.另外:1)三张中含一对的组合有多少张?(...

    共回答了20个问题采纳率:95% 这个题目我喜欢 所有组合为:C(52,5) 1.A组为三张不关联明牌,组合:52*48*44,与B组二张暗牌组成一个对子.B的组合为:(12-3)*(52-12).概 ...

  2. java利用复循环洗牌算法_随机洗牌算法

    今天偶然看到群里的朋友说道,面试被问如何将扑克牌随机洗牌输出.笔者觉得这道题挺有意思而且挺开放性,有多种不同的实现方式.然后我就随手写了一个算法,仔细一想这个算法的优化空间挺大,于是又写出三种算法. ...

  3. Java将扑克牌花色和数字组合成52张扑克牌集合 并完成在牌堆中抽牌的操作

    #JavaSe# 在只有扑克牌颜色数组和数字数组的情况下,合成扑克牌,并且完成抽牌操作 定义一个扑克牌类 public class Card {private String[] point={&quo ...

  4. python随机抽号_Python 创建扑克牌,并实现随机抽牌、排序、洗牌等功能

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 以下文章来源于Z先生点记,作者 zeroing 转载地址 https://mp. ...

  5. 洗牌、发牌算法 (打乱扑克牌顺序)

      #include <stdio.h> #include <stdlib.h> #include <time.h> int  d[6]; int  i,n,a,b ...

  6. 随机洗牌算法 银行家算法

    1. 随机洗牌算法 https://blog.csdn.net/qq_26399665/article/details/79831490 Fisher-Yates Shuffle算法 最早提出这个洗牌 ...

  7. 用python实现纸牌游戏的随机抽牌洗牌过程(item系列几个内置方法的实例)

    1.namedtuple:命名元组,可以创建一个没有方法只有属性的类 from collections import namedtuple card = namedtuple('card',['ran ...

  8. C#:实现随机洗牌Knuth-Durstenfeld Shuffle算法​(附完整源码)

    C#:实现随机洗牌Knuth-Durstenfeld Shuffle算法 public static void Shuffle<T>(T[] a) {Random rnd = new Ra ...

  9. 随机洗牌算法之Knuth-Durstenfeld Shuffle

    问题 设计一个公平的洗牌算法 问题分解 首先,必然明确这是一个随机算法 其次,要考虑公平 问题剖析 关于随机 看到随机我们大多数时候想起来的是,把所有的数都放到一个数组里,每次取两个数进行交换,随机 ...

  10. 斗地主棋牌类游戏中的洗牌和发牌算法

    前言 洗牌和发牌是棋牌类游戏中,非常重要的两个关键节点,而这两个关键节点涉及的算法,很多同学非常感兴趣,今天,我们就以NodeJS环境为例,通过JS代码给大家解说洗牌和发牌算法. 一. 洗牌算法 1. ...

最新文章

  1. (一)七种AOP实现方法
  2. Cognitive Inference:认知推理下的常识知识库资源、常识推理测试评估与中文实践项目索引...
  3. 如何提高模型性能?这四大方法值得尝试 | CSDN 博文精选
  4. 前端学python有什么用-杭州前端需要学习python
  5. linux下dns设置详解
  6. C++ Primer 5th笔记(10)chapter10 泛型算法 :迭代器
  7. 反思读别人代码的思路
  8. 韩信大招:一致性哈希
  9. 关于PLSQL Developer报动态执行表不可访问,本会话的自动统计被禁止错的解决方法 .
  10. ajax post提交数据_第三十五天JavaScript中的ajax
  11. autofac获取全局Container
  12. Oracle锁庞大大引见
  13. 微信小程序中图表可视化
  14. MATLAB之fprintf
  15. Boom 3D 1.2.2 特别版 Mac 3D环绕音效增强工具
  16. w ndows热键,Window 10 优雅的快捷键
  17. Jsoup实现网络爬虫抓取数据
  18. Hazelcast IMDG参考中文版手册-第二章-入门
  19. 评价指标(一)精确率,召回率,F1-score
  20. 手残把下载文件夹位置移动到了D盘根目录,导致了一系列问题的解决方法

热门文章

  1. django-数据库[ 基本操作 ]
  2. 25个移动APP图表设计欣赏(译)
  3. java分号_java – 为什么这些分号不会产生错误?
  4. 会议摘要怎么写?这篇论文手把手教你
  5. 功率因素校正(PFC)技术!
  6. Python生成 一维条码
  7. 如何在win10上显示隐藏文件
  8. 一加手机怎么root权限_一加手机怎么获取root权限?
  9. matlab制作科学计算器,基于MATLAB科学计算器
  10. 怎样挖掘搜索关键词?