1 1 -1 -1 1 1 -1
java版本的代码实现:
package cn.cat.algorithm;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class GambleGoldFlower {
/**
* 分析:
* 1、校验出入,数值为2—A,13种牌,每种牌四张。
* 2、给每种牌号都设定分值,2为2分,3为3分,以此类推,A为14分。
* 3、比较牌型。豹子加分3000000分,顺子加2000000分,对子加1000000分,
* 普通牌型则直接把三张牌对应的分值,由大到小分值顺序拼凑成一个数字,例如K52 -》 130502
*
* 注意:
* 1、比较牌型时优先从大牌开始匹配,例如AAA是属于对子,但是也是豹子,应该优先匹配为大牌,即豹子。
* 2、优先比较牌型,牌型大的则赢,如果牌型一致或者不是特殊牌型(豹子、顺子、对子),则比较牌号的大小。
*
* @Description:
* @author gwj
* @Created 2018年4月12日 下午2:32:24
* @param args
* @throws InterruptedException
*/
@SuppressWarnings("resource")
public static void main(String[] args) throws InterruptedException {
System.out.println("请输入牌型(单个空格隔开每组牌):");
Scanner scanner = new Scanner(System.in);
String[] part = scanner.nextLine().split(" ");
if (part.length % 2 != 0) {
throw new IllegalArgumentException("输入的牌局数为" + part.length + ",局数必须是偶数!");
}
System.out.println("牌型比较结果:");
for (int i = 0; i < part.length - 1; i++) {
System.out.print(play(part[i], part[++i]));
System.out.print(" ");
}
}
/** 开始游戏
* @Description:
* @author gwj
* @Created 2018年4月16日 上午11:27:38
* @param player1CardStr 玩家一的牌
* @param player2CardStr 玩家而的牌
* @return 返回游戏结果。1表示玩家1胜利,-1表示玩家2胜出,0表示平局。
*/
private static int play(String player1CardStr, String player2CardStr) {
//1.判断牌号是否非法
if (isIllegalCardNo(player1CardStr)) {
System.out.println(player1CardStr + "是不合法的牌");
return -2;
}
if (isIllegalCardNo(player2CardStr)) {
System.out.println(player2CardStr + "是不合法的牌");
return -2;
}
//2.分割出玩家的每张牌号
String[] player1Card = splitCardNoAndAsc(player1CardStr);
String[] player2Card = splitCardNoAndAsc(player2CardStr);
//3.判断两个玩家的牌合在一起,看同一种牌的数量没有超过4张。
String[] mergeCardNo = new String[]{
player1Card[0], player1Card[1], player1Card[2],
player2Card[0], player2Card[1], player2Card[2]
};
if (hasOverFourForSameCardClass(mergeCardNo)) {
System.out.println("两个玩家的牌有冲突,同一个牌号超过4张。");
return -2;
};
//4.计算牌型的分值
int player1Score = calcCardPatternScore(player1Card);
int player2Score = calcCardPatternScore(player2Card);
//5.比较分值
int result;
if (player1Score > player2Score) {
result = 1;
} else if (player1Score < player2Score) {
result = -1;
} else {
result = 0;
}
return result;
}
/** 校验牌编号是否非法
* @Description:
* @author gwj
* @Created 2018年4月13日 下午5:16:49
* @param cardNo
* @return true表示非法
*/
private static boolean isIllegalCardNo(String cardNo) {
return !cardNo.matches("([23456789JQKA]|10){3}");
}
/** 将一组牌号进行分割出每张独立的牌,并进行升序排序
* @Description:
* @author gwj
* @Created 2018年4月13日 下午5:43:15
* @param cardNo 牌号
* @return 返回一个数组,一个元素表示一张牌。
*/
private static String[] splitCardNoAndAsc(String cardNo) {
String[] cardNos = new String[3];
char[] charArray = cardNo.toCharArray();
if (cardNo.length() == 3) {
//没有出现10的牌号,故直接分解为一个字符就是一个牌号
cardNos[0] = String.valueOf(charArray[0]);
cardNos[1] = String.valueOf(charArray[1]);
cardNos[2] = String.valueOf(charArray[2]);
} else {
int charIndex = 0;
int resultInex = 0;
while (charIndex < charArray.length) {
if (charArray[charIndex] == '1' && charArray[charIndex + 1] == '0') {
//出现10的牌号,则一次获取两个字符,组成10。
cardNos[resultInex] = String.valueOf(charArray, charIndex, 2);
charIndex ++;
} else {
cardNos[resultInex] = String.valueOf(charArray[charIndex]);
}
//循环累加
charIndex ++;
resultInex ++;
}
}
//将牌号转换为分值,便于进行排序。
int[] scores = calcCardNoScore(cardNos);
//将牌分值按顺序进行升序排序,使用冒泡法。
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3 - i - 1; j++) {
if (scores[j] > scores[j+1]) {
//交换分值数组
int tempScore = scores[j];
scores[j] = scores[j+1];
scores[j+1] = tempScore;
//同时修改牌号数组顺序
String tempCardNo = cardNos[j];
cardNos[j] = cardNos[j+1];
cardNos[j+1] = tempCardNo;
}
}
}
return cardNos;
}
/** 相同的牌种是否有超过4张。
* @Description:
* @author gwj
* @Created 2018年4月13日 下午5:42:06
* @param cardNos
* @return true表示有超过4张同种牌。
*/
private static boolean hasOverFourForSameCardClass(String[] cardNos) {
Map cardCountMap = new HashMap();
for (String cardNo : cardNos) {
Integer count = cardCountMap.get(cardNo) == null ? 0 : cardCountMap.get(cardNo);
//当前牌种数量加1
count ++;
//同种牌数量超过4张
if (count > 4) {
return true;
}
cardCountMap.put(cardNo, count);
}
return false;
}
/** 将牌号转换为分值
* @Description:
* @author gwj
* @Created 2018年4月16日 上午11:08:19
* @param cardNos
* @return
*/
private static int[] convertToScoreForCardNo(String[] cardNos) {
//将牌型转换为牌分值
int len = cardNos.length;
int[] scores = new int[len];
for (int i = 0; i < len; i++) {
scores[i] = calcCardNoScore(cardNos[i]);
}
return scores;
}
/** 升序排序
* @Description:
* @author gwj
* @Created 2018年4月16日 上午11:11:50
* @param arr
* @return 返回排序后的arr参数数组
*/
private static int[] orderAsc(int[] arr) {
int len = arr.length;
//将牌分值按顺序进行升序排序,使用冒泡法。
for (int i = 0; i < len; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
//返回当前数组
return arr;
}
/** 计算牌号分值
* @Description:
* @author gwj
* @Created 2018年4月13日 下午5:55:24
* @param cardNos 牌号集合
* @return 牌号分值集合
*/
private static int[] calcCardNoScore(String[] cardNos) {
int[] score = new int[cardNos.length];
for (int i = 0; i < score.length; i++) {
score[i] = calcCardNoScore(cardNos[i]);
}
return score;
}
/** 计算牌号分值
* @Description:
* @author gwj
* @Created 2018年4月13日 下午5:55:24
* @param cardNo 牌号
* @return 牌号分值
*/
private static int calcCardNoScore(String cardNo) {
int score = 0;
if (cardNo.matches("\\d{1,2}")) {
score += Integer.valueOf(cardNo);
} else {
if (cardNo.equals("J")) {
score += 11;
} else if (cardNo.equals("Q")) {
score += 12;
} else if (cardNo.equals("K")) {
score += 13;
} else if (cardNo.equals("A")) {
score += 14;
}
}
return score;
}
/** 计算牌型分值
* @Description:
* @author gwj
* @Created 2018年4月13日 下午5:55:24
* @param cardNos 集合
* @return 牌型分值。如果不是特殊牌型((豹子、顺子、对子),则返回0。
*/
private static int calcCardPatternScore(String[] cardNos) {
int score = 0;
if (isLeopardCardPattern(cardNos)) {
//豹子,三张牌号都一样,随便拿取一个元素作为加分牌号。
score = 3000000 + calcCardNoScore(cardNos[2]);
} else if (isSequenceCardPattern(cardNos)) {
//顺子,直接给最大牌号进行加分。
score = 2000000 + calcCardNoScore(cardNos[2]);
} else if (isPairCardPattern(cardNos)) {
//对子,对子比较特殊,直接找出对子牌号来加分。
String pairCardNo = cardNos[0];
if (cardNos[1].equals(cardNos[2])) {
pairCardNo = cardNos[1];
}
score = 1000000 + calcCardNoScore(pairCardNo);
} else {
//普通排序,由大牌到小牌按顺序拼接分值。
int[] scores = calcCardNoScore(cardNos);
String scoreSum = "";
for (int i = scores.length -1 ; i >= 0; i--) {
if (scores[i] < 10) {
//一个数的分值,增加0来补齐两位数。
scoreSum = scoreSum + "0" + scores[i];
} else {
scoreSum = scoreSum + scores[i];
}
}
score = Integer.parseInt(scoreSum);
}
return score;
}
/** 是否豹子牌型
* @Description:
* @author gwj
* @Created 2018年4月16日 上午9:51:48
* @param cardNos 牌号集
* @return true表示豹子。
*/
private static boolean isLeopardCardPattern(String[] cardNos) {
//豹子牌型:三个牌号一样。
return cardNos[0].equals(cardNos[1]) && cardNos[1].equals(cardNos[2]);
}
/** 是否对子牌型
* @Description:
* @author gwj
* @Created 2018年4月16日 上午9:54:09
* @param cardNos
* @return true表示对子。
*/
private static boolean isPairCardPattern(String[] cardNos) {
//对子牌型:存在有两张一样牌号的牌。
return cardNos[0].equals(cardNos[1])
|| cardNos[0].equals(cardNos[2])
|| cardNos[1].equals(cardNos[2]);
}
/** 是否顺子牌型
* @Description:
* @author gwj
* @Created 2018年4月16日 上午9:54:09
* @param cardNos
* @return true表示顺子。
*/
private static boolean isSequenceCardPattern(String[] cardNos) {
//转换为分值并排序
int[] score1 = orderAsc(convertToScoreForCardNo(cardNos));
//如果是顺子,则分值是每次加1。
return (score1[0] + 1 == score1[1]) && (score1[1] + 1 == score1[2]);
}
}