一道有意思的ACM题——Poker Hands的解法

A poker deck contains 52 cards - each card has a suit which is one of clubs, diamonds, hearts, or spades (denoted C, D, H, S in the input data). Each card also has a value which is one of 2, 3, 4, 5, 6, 7, 8, 9, 10, jack, queen, king, ace (denoted 2, 3, 4, 5, 6, 7, 8, 9, T, J, Q, K, A). For scoring purposes, the suits are unordered while the values are ordered as given above, with 2 being the lowest and ace the highest value.

A poker hand consists of 5 cards dealt from the deck. Poker hands are ranked by the following partial order from lowest to highest 
• High Card. Hands which do not fit any higher category are ranked by the value of their highest card. If the highest cards have the same value, the hands are ranked by the next highest, and so on. 
• Pair. 2 of the 5 cards in the hand have the same value. Hands which both contain a pair are ranked by the value of the cards forming the pair. If these values are the same, the hands are ranked by the values of the cards not forming the pair, in decreasing order. 
• Two Pairs. The hand contains 2 different pairs. Hands which both contain 2 pairs are ranked by the value of their highest pair. Hands with the same highest pair are ranked by the value of their other pair. If these values are the same the hands are ranked by the value of the remaining card. 
• Three of a Kind. Three of the cards in the hand have the same value. Hands which both contain three of a kind are ranked by the value of the 3 cards. 
• Straight. Hand contains 5 cards with consecutive values. Hands which both contain a straight are ranked by their highest card. 
• Flush. Hand contains 5 cards of the same suit. Hands which are both flushes are ranked using the rules for High Card. 
• Full House. 3 cards of the same value, with the remaining 2 cards forming a pair. Ranked by the value of the 3 cards. 
• Four of a kind. 4 cards with the same value. Ranked by the value of the 4 cards. 
• Straight flush. 5 cards of the same suit with consecutive values. Ranked by the highest card in the hand. 
Your job is to compare several pairs of poker hands and to indicate which, if either, has a higher rank. 
Input Specification

Several lines, each containing the designation of 10 cards: the first 5 cards are the hand for the player named “Black” and the next 5 cards are the hand for the player named “White.”

Output Specification

For each line of input, print a line containing one of: 
Black wins. 
White wins. 
Tie.

Sample Input 
2H 3D 5S 9C KD 2C 3H 4S 8C AH 
2H 4S 4C 2D 4H 2S 8S AS QS 3S 
2H 3D 5S 9C KD 2C 3H 4S 8C KH 
2H 3D 5S 9C KD 2D 3H 5C 9S KH

Sample Output 
White wins. 
Black wins. 
Black wins. 
Tie.

首先要看懂题目的意思,其实这道题就是一道小型的同花顺,非常有意思,这里我大致翻译一下。

一副扑克牌去掉大小王剩52张牌,C,D,H,S表示梅花,方块,红桃,黑桃,2, 3, 4, 5, 6, 7, 8, 9, T, J, Q, K, A表示牌的大小。每次十张牌2H 3D 5S 9C KD 2C 3H 4S 8C AH,前五张是“Black”之后是“White”。牌面的大小比较分为9个等级。从大到小依次排列。 
1、不属于任何一个高等级的牌,就是我们俗话说的全单牌还不同花。同属于这一等级的话自然是先比最大的牌,一样则依次往下比较。 
2、有一个对子,剩下三张单牌。同属于这一等级就先比较对子大小,然后比单牌。 
3、有两个对子,剩一张单牌。同属于这一等级就先比较最大的对子,一样则再比较第二对,最后比较单牌。 
4、有三张牌大小一样,剩两张单牌。同属于这一等级就比较三张的大小。 
5、顺子。同属于这一等级比较最大的那张牌就好。 
6、同花。同属于这一等级按照第一等级的比较规则比较大小。 
7、三张带对子。同属于这一等级比较三张的大小。 
8、有四张牌一样。同属于这一等级比较四张的大小。 
9、同花顺。同属于这一等级比较最大的牌就好。

然后我先对我的思路做一个总的概述,我的策略是先把字符串转换成整数,然后对牌面大小进行排序,用两个二维数组分别保存黑和白。再得到每副牌的等级,等级相同的话再进行比较。 
最后直接上代码吧,这里是用C写的。

#include <stdio.h>
#include <stdlib.h>

typedef int (*R)[2];
int ctoi_array[5][2];

//得到每副牌的等级
int rank(int dest[][2])
{
	int one=dest[0][0] == dest[1][0];
	int two=dest[1][0] == dest[2][0];
	int three=dest[2][0] == dest[3][0];
	int four=dest[3][0] == dest[4][0];
	int straight,flush;
	int i=0;
	while(i<4)
	{
		if(dest[i][0]+1 != dest[i+1][0])
		{
			straight=0;
			break;
		}
		i++;
		if(i==4)
			straight=1;
	}
	i=0;
	while(i<4)
	{
		if(dest[i][1] != dest[i+1][1])
		{
			flush=0;
			break;
		}
		i++;
		if(i==4)
			flush=1;
	}
	if(one || two || three || four)
	{
		if((one && two && three) || (two && three && four))
			return 8;
		if((one && two && four) || (one && three && four))
			return 7;
		if((one && two) || (two && three) || (three && four))
		{
			if(flush)
				return 6;
			else 
				return 4;
		}
		if((one && three) || (one && four) || (two && four))
		{
			if(flush)
				return 6;
			else
				return 3;
		}
		if(flush)
			return 6;
		else
			return 2;
	}
	else if(straight)
	{
		if(flush)
			return 9;
		else
			return 5;
	}
	else
	{
		if(flush)
			return 6;
		else 
			return 1;
	}
}

//将二维字符数组转化成二维整数数组
R ctoi(char c_dest[][2])
{
	int i,j;
	for(i=0 ;i<5 ;i++)
	{
		for(j=0 ;j<2 ;j++)
		{
			if(c_dest[i][j]<='9' && c_dest[i][j]>='2')
				ctoi_array[i][j]=c_dest[i][j]-'0';
			else
			{
				switch(c_dest[i][j])
				{
					case 'T':ctoi_array[i][j]=10;break;
					case 'J':ctoi_array[i][j]=11;break;
					case 'Q':ctoi_array[i][j]=12;break;
					case 'K':ctoi_array[i][j]=13;break;
					case 'A':ctoi_array[i][j]=14;break;
					case 'C':ctoi_array[i][j]=1;break;
					case 'D':ctoi_array[i][j]=2;break;
					case 'H':ctoi_array[i][j]=3;break;
					case 'S':ctoi_array[i][j]=4;break;
				}
			}
		}
	}
	for(i=0 ;i<5 ;i++)
	{
		for(j=0 ;j<4-i ;j++)
		{
			if(ctoi_array[j][0] > ctoi_array[j+1][0])
			{
				int tmp=ctoi_array[j][0];
				ctoi_array[j][0]=ctoi_array[j+1][0];
				ctoi_array[j+1][0]=tmp;
			}
		}
	}
	return ctoi_array;
}

//等级相同时的比较细则,返回1表示黑赢,-1表示白赢,0表示平局
int equal_rank(int black[][2],int white[][2],int _rank)
{
	int i,j=0,k=0;
	int remain_b[3],remain_w[3];
	int pair_b[2],pair_w[2];
	int three_kind_b,three_kind_w,four_kind_b,four_kind_w;
	if(1==_rank || 6==_rank)
	{
		for(i=4 ;i>=0 ;i--)
		{
			if(black[i][0] == white[i][0])
				continue;
			else if(black[i][0] > white[i][0])
				return 1;
			else
				return -1;
		}
		return 0;
	}
	if(2==_rank)
	{
		for(i=0 ;i<4 ;i++)
		{
			if(black[i][0] == black[i+1][0])
			{
				pair_b[0]=black[i][0];
			}
			if(white[i][0] == white[i+1][0])
			{
				pair_w[0]=black[i][0];
			}	
		}
		for(i=0 ;i<3 ;i++)
		{
			if(pair_b[0] == black[j][0])
				j++;
			remain_b[i]=black[j][0];
			j++;
			if(pair_w[0] == white[k][0])
				k++;
			remain_w[i]=white[k][0];
			k++;
		}
		if(pair_b[0] > pair_w[0])
			return 1;
		else if(pair_b[0] < pair_w[0])
			return -1;
		else
		{
			for(i=2 ;i>=0 ;i--)
			{
				if(remain_b[i] == remain_w[i])
					continue;
				else if(remain_b[i] > remain_w[i])
					return 1;
				else
					return -1;
			}
			return 0;
		}
	}
	if(3==_rank)
	{
		for(i=0 ;i<4 ;i++)
		{
			if(black[i][0] == black[i+1][0])
			{
				pair_b[j]=black[i][0];
				j++;
			}
			if(white[i][0] == white[i+1][0])
			{
				pair_w[k]=white[i][0];
				k++;
			}
		}
		for(i=1 ;i>=0 ;i--)
		{
			if(pair_b[i] == pair_w[i])
				continue;
			else if(pair_b[i] > pair_w[i])
				return 1;
			else
				return -1;
		}
		for(i=0 ;i<5 ;i++)
		{
			if(black[i][0] != pair_b[0] && black[i][0] != pair_b[1])
				remain_b[0]=black[i][0];
			if(white[i][0] != pair_w[0] && white[i][0] != pair_w[1])
				remain_w[0]=white[i][0];
		}
		if(remain_w[0] == remain_b[0])
			return 0;
		else if(remain_b[0] > remain_w[0])
			return 1;
		else 
			return -1;
	}
	if(4==_rank || 7==_rank)
	{
		for(i=0 ;i<3 ;i++)
		{
			if(black[i][0] == black[i+1][0] && black[i][0] == black[i+2][0])
				three_kind_b=black[i][0];
			if(white[i][0] == white[i+1][0] && white[i][0] == white[i+2][0])
				three_kind_w=white[i][0];
		}
		if(three_kind_b > three_kind_w)
			return 1;
		else
			return -1;
	}
	if(5==_rank || 9==_rank)
	{
		if(black[4][0] > white[4][0])
			return 1;
		else if(black[4][0] < white[4][0])
			return -1;
		else 
			return 0;
	}
	if(8==_rank)
	{
		for(i=0 ;i<2 ;i++)
		{
			if(black[i][0]==black[i+1][0] && black[i][0]==black[i+2][0] && black[i][0]==black[i+3][0])
				four_kind_b=black[i][0];
			if(white[i][0]==white[i+1][0] && white[i][0]==white[i+2][0] && white[i][0]==white[i+3][0])
				four_kind_w=white[i][0];
		}
		if(four_kind_b > four_kind_w)
			return 1;
		else
			return -1;
	}
}

int main()
{
	freopen("flush_straight.txt","r",stdin);//输入重定向操作,便于调试
	char buf[30];
	char c_black[5][2],c_white[5][2];
	int i_black[5][2],i_white[5][2];
	R tmp_black,tmp_white;
	int rank_black,rank_white;
	int i,j,k=0;
	while(gets(buf)!=NULL)
	{
		for(i=0 ;i<5 ;i++)
		{
			for(j=0 ;j<2 ;j++)
			{
				if(buf[k]==' ')
					k++;
				c_black[i][j]=buf[k];      //从一行牌中得到黑牌和白牌
				c_white[i][j]=buf[k+15];
				k++;
			}
		}
		k=0;
		tmp_black=ctoi(c_black);
		for(i=0 ;i<5 ;i++)
		{
			for(j=0 ;j<2 ;j++)
			{
				i_black[i][j]=tmp_black[i][j];
			}
		}
		tmp_white=ctoi(c_white);
		for(i=0 ;i<5 ;i++)
		{
			for(j=0 ;j<2 ;j++)
			{
				i_white[i][j]=tmp_white[i][j];
			}
		}
		rank_black=rank(i_black);
		rank_white=rank(i_white);
		if(rank_black > rank_white)
		{
			printf("Black wins.\n");
		}
		else if(rank_black < rank_white)
		{
			printf("White wins.\n");
		}
		else
		{
			int ret=equal_rank(i_black,i_white,rank_black);
			if(1==ret)
				printf("Black wins.\n");
			else if(-1==ret)
				printf("White wins.\n");
			else
				printf("Tie.\n");
		}
	}		
	return 0;
}


最后我想再总结两句,这道题按照逻辑慢慢来一般都能解出。然后我觉得二维数组的传参和作为函数的返回值是一个有点偏但又很实用的知识点,我就是通过这道题才掌握的。还有我觉得代码有点繁琐了,应该还能优化或者有更好的算法,欢迎来和我讨论。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值