[week2]洗牌
题意
瑞神HRZ因为疫情在家闲得无聊,同时他又非常厉害,所有的课对他来说都是水一水就能拿A+,所以他无聊,找来了另外三个人:咕咕东,腾神以及zjm来打牌(天下苦瑞神久矣)。
【菜鸡凝视????】
显然,牌局由四个人构成,围成一圈。我们称四个方向为北 东 南 西。对应的英文是North,East,South,West。游戏一共由一副扑克,也就是52张构成。开始,我们指定一位发牌员(东南西北中的一个,用英文首字母标识)开始发牌,发牌顺序为顺时针,发牌员第一个不发自己,而是发他的下一个人(顺时针的下一个人)。这样,每个人都会拿到13张牌。
现在我们定义牌的顺序,首先,花色是(梅花)<(方片)<(黑桃)<(红桃),(输入时,我们用C,D,S,H分别表示梅花,方片,黑桃,红桃,即其单词首字母)。对于牌面的值,我们规定2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < T < J < Q < K < A。
现在你作为上帝,你要从小到大排序每个人手中的牌,并按照给定格式输出。(具体格式见输出描述和样例输出)。
Input
输入包含多组数据
每组数据的第一行包含一个大写字符,表示发牌员是谁。如果该字符为‘#’则表示输入结束。
接下来有两行,每行有52个字符,表示了26张牌,两行加起来一共52张牌。每张牌都由两个字符组成,第一个字符表示花色,第二个字符表示数值。
Output
输出多组数据发牌的结果,每组数据之后需要额外多输出一个空行!!!!!
每组数据应该由24行的组成,输出按照顺时针方向,始终先输出South Player的结果,每位玩家先输出一行即玩家名称(东南西北),接下来五行,第一行和第五行输出固定格式(见样例),第二行和第四行按顺序和格式输出数值(见样例),第三行按顺序和格式输出花色(见样例)。
输入样例
N
CTCAH8CJD4C6D9SQC7S5HAD2HJH9CKD3H6D6D7H3HQH4C5DKHKS9
SJDTS3S7S4C4CQHTSAH2D8DJSTSKS2H5D5DQDAH7C9S8C8S6C2C3
输出样例
分析
【菜鸡凝视后】分析题目可知,解决这道题的关键在于自定义牌面大小顺序以及实现玩家的顺时针顺序。
- 如何实现玩家的顺时针顺序?
根据题目的要求,可以发现在发牌和洗牌之后输出的两个操作中都要保证玩家东西南北的顺时针顺序不变。也就是说,可以将四位玩家N、E、S、W看作一个圈,不论从谁开始发牌或者输出,都是从开始处顺时针转下去。
根据这个特性我们就可以联想到循环队列。可以按任何一种顺时针玩家顺序出入队列中,只要将队首的玩家不断循环排到队尾,即可实现循环队列。
发牌阶段 —— 第一个拿到牌的玩家总为发牌者的下家,因此在每次发牌开始阶段,将队列调整到发牌者的下家位于队首即可(也可以理解为发牌者在队尾)。在每张牌发放后,将当前拿牌玩家放到队尾。不断循环,直到52张牌发放结束。本代码中为player队列。
洗牌及输出阶段 —— 因为输出顺序永远固定,所以可以为了省事直接按输出玩家的顺序定义一个输出数组,本代码中为output数组。在每次输出前给当前待输出玩家洗牌即可。
- 自定义牌面大小顺序
在最开始构思的时候,最先想到的就是一般的自定义比较函数,也就是依次比较两张牌所有花色以及面值的情况。但是,很明显这个比较量太大,很难书写,而我也没有想到解决这个问题的办法。
后来突然灵光一现????,发现待比较的面值和花色虽然没有少到方便直接定义比较,但是也没有非常多。因此我想到,将它们按照大小顺序放入两个string字符串中,将所有符号统一视作单个字符(不区分字母和数字),利用它们在字符串中的位置(字符串数组下标)来比较。
所以,比较函数就定义为首先比较花色,返回它们在花色字符串color中的位置下标大小;若花色相同,返回它们在面值字符串value中的位置下标大小。
总结
- 认真读题,规范输出!不要总把宝贵时间浪费在查找输出错误上????
- 记不得在每次循环之后把需要清空的结构进行清空的错误真是屡错不改????
- 老是出现利用for进行多重循环的时候混用下标变量【三脸懵逼】,书写代码应该仔细一点,避免一些低级小错误需要消耗不少时间调试才能发现的情况。
代码
//
// main.cpp
// lab3
//
//
#include <iostream>
#include <string>
#include <iomanip>
#include <vector>
#include <queue>
#include <map>
#include <string>
using namespace std;
map<char, vector<pair<char, char>>> card; //四位玩家的持牌
map<char,string> name; //输出玩家
queue<char> player; //玩家顺序
string color="CDSH",value="23456789TJQKA"; //花色和面值按升序排列
char output[4]={'S','W','N','E'}; //输出顺序
bool cmp(const pair<char, char> &p1,const pair<char,char> &p2 ) //花色和面值排序
{
if( p1.first != p2.first ) //先比较花色
return color.find(p1.first) < color.find(p2.first); //返回花色在字符串中下标的大小比较
return value.find(p1.second) < value.find(p2.second); //其次比较面值
}
int main()
{
char start; //发牌人
pair<char, char> c; //当前发的牌
cin>>start;
player.push('N'); //按NESW的顺时针顺序输入到队列中
player.push('E');
player.push('S');
player.push('W');
name['N']="North player:";
name['E']="East player:";
name['S']="South player:";
name['W']="West player:";
while( start != '#' )
{
while( !player.empty() ) //将队列顺序调整为以发牌人的下家为队首的顺序
{
if( player.front() == start ) //若当前队首即为发牌人,则将其移到队尾即可
{
player.push(player.front());
player.pop();
break;
}
player.push(player.front()); //依次将发牌人前的玩家移到队尾
player.pop();
}
for( int i = 0 ; i < 52 ; i++ ) //发牌
{
cin>>c.first>>c.second; //一次输入一张牌的花色和面值
card[player.front()].push_back(c); //将其插入当前队首玩家的持牌数组中
player.push(player.front()); //将该玩家排到队尾
player.pop();
}
for( int i = 0 ; i < 4 ; i++ )
{
sort(card[output[i]].begin(), card[output[i]].end(), cmp); //将牌排序
cout<<name[output[i]]<<endl; //输出玩家
cout<<"+---+---+---+---+---+---+---+---+---+---+---+---+---+"<<endl;
for( int j = 0 ; j < 39 ; j++ ) //输出该玩家持牌顺序
{
if( j > 12 && j < 26 )
cout<<"| "<<card[output[i]][j%13].first<<" ";
else
cout<<"|"<<card[output[i]][j%13].second<<" "<<card[output[i]][j%13].second;
if( j%13 == 12 )
cout<<"|"<<endl;
}
cout<<"+---+---+---+---+---+---+---+---+---+---+---+---+---+"<<endl;
card[output[i]].clear(); //依次将所有玩家的卡牌数组清空
}
cout<<endl;
cin>>start;
}
return 0;
}