注:以下算法说明仅限一副牌(不包含大小王)的情况
1、炸金花规则说明(大家都懂的,这里做简单描述):
1)玩家每人3张牌;
2)牌面大小2、3、4、5、6、7、8、9、10(用T表示),J、Q、K、A,大小依次递增;
3)牌的花色有黑桃(用H表示)、红心(用X表示)、梅花(用M表示)、方块(用F表示),大小依次递减;
4)牌有豹子(3张牌数字大小相同)、同花顺、同花(此种未实现,有兴趣的玩家可以自己加上,或者欢迎和我交流)、顺子、对子、散牌几种类型,大小依次递减;
5)玩家先比牌的类型,如先按照4)中的规则比较,如:当都是豹子时,则比较豹子的牌面值大小(如H9X9M9>F8X8M8;类型相同时,按照2)中的牌面值比较,如:H9X9M2>F8X8HA,M9H9M2<F9X9HA等,详情请自行搜索或者查看代码注释或者看测试用例说明;
2、实现算法特点:
1)采用面向对象方式实现,分别构造牌面值的对象(枚举)、牌的花色对象(枚举)、玩家三张牌的类型(枚举,如豹子、同花顺等)、一张扑克牌对应的对象(一张牌有一个牌面值属性、一个花色属性)、玩家对象(玩家有3张扑克牌,牌的类型属性);
2)主要是通过Java Comparable 接口的compareTo实现比较功能,很方便对玩家手中的牌进行排序(调用Collections.sort方法实现),同事避免了很多if else 比较;
3、上代码:
1)牌面值枚举
/*
* <pre>
* 文 件 名: PorkActor.java
* 描 述: <描述>
* 修改时间: 2014-6-15
* </pre>
*/
package com.dobuy.zhajinhua;
/**
* <pre>
* 每张扑克牌的牌面数字
*
* </pre>
*/
public enum PorkActor
{
TWO('2'), THREE('3'), FOUR('4'), FIVE('5'), SIX('6'), SEVEN('7'), EIGHT('8'), NIME('9'), TEN('T'), J('J'), Q('Q'), K(
'K'), A('A');
private char num;
private PorkActor(char num)
{
this.num = num;
}
/**
* 获取 num
*
* @return 返回 num
*/
private char getNum()
{
return num;
}
/**
* <pre>
* 根据牌面数字找到扑克牌对应的牌面枚举对象
*
* @param num
* @return
* </pre>
*/
public static PorkActor getPorkActor(char num)
{
for (PorkActor porkActor : PorkActor.values())
{
if (porkActor.getNum() == num)
{
return porkActor;
}
}
return null;
}
}
2)牌的花色枚举
/*
* <pre>
* 文 件 名: PorkColor.java
* 描 述: <描述>
* 修改时间: 2014-6-15
* </pre>
*/
package com.dobuy.zhajinhua;
/**
* <pre>
* 扑克牌花色
*
* </pre>
*/
public enum PorkColor
{
F('F'), M('M'), X('X'), H('H');
/**
* 牌的花色
*/
private char color;
private PorkColor(char color)
{
this.color = color;
}
/**
* <pre>
* 根据花色字符查找扑克牌的花色枚举对象
*
* @param color
* @return
* </pre>
*/
public static PorkColor getPorkColor(char color)
{
for (PorkColor porkColor : PorkColor.values())
{
if (porkColor.color == color)
{
return porkColor;
}
}
return null;
}
}
3)一张扑克牌
/*
* <pre>
* 文 件 名: Pork.java
* 描 述: <描述>
* 修改时间: 2014-6-15
* </pre>
*/
package com.dobuy.zhajinhua;
/**
* <pre>
* 一张扑克牌对象
* 1.实现Comparable接口,通过compareTo方法进行比较大小
* 2.比较规则:
* 1)先看牌面数字,数字大的就大;
* 2)牌面数字相同时,花色大的就大;
*
* </pre>
*/
public class Pork implements Comparable<Pork>
{
/**
* 扑克牌的牌面数字
*/
private PorkActor porkActor;
/**
* 扑克牌的花色
*/
private PorkColor porkColor;
/**
* 长度为2的字符串,接收扑克牌的数字和花色:第0位为数字,第1位为花色 <默认构造函数>
*/
public Pork(String porkAttr)
{
char porkActor = porkAttr.charAt(1);
char porkColor = porkAttr.charAt(0);
setPorkActor(PorkActor.getPorkActor(porkActor));
setPorkColor(PorkColor.getPorkColor(porkColor));
}
/**
* 获取 porkActor
*
* @return 返回 porkActor
*/
public PorkActor getPorkActor()
{
return porkActor;
}
/**
* 设置 porkActor
*
* @param 对porkActor进行赋值
*/
public void setPorkActor(PorkActor porkActor)
{
this.porkActor = porkActor;
}
/**
* 获取 porkColor
*
* @return 返回 porkColor
*/
public PorkColor getPorkColor()
{
return porkColor;
}
/**
* 设置 porkColor
*
* @param 对porkColor进行赋值
*/
public void setPorkColor(PorkColor porkColor)
{
this.porkColor = porkColor;
}
/**
* 重载方法
*
* @return
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((porkActor == null) ? 0 : porkActor.hashCode());
result = prime * result + ((porkColor == null) ? 0 : porkColor.hashCode());
return result;
}
/**
* 重载方法
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pork other = (Pork)obj;
if (porkActor != other.porkActor)
return false;
if (porkColor != other.porkColor)
return false;
return true;
}
/**
* 重载方法
*
* @param o
* @return
*/
@Override
public int compareTo(Pork o)
{
// 先去比较牌面大小
int compare = getPorkActor().compareTo(o.getPorkActor());
// 牌面相同时
if (compare == 0)
{
// 比较花色
return getPorkColor().compareTo(o.getPorkColor());
}
return compare;
}
/**
* 重载方法
*
* @return
*/
@Override
public String toString()
{
return "Pork [porkActor=" + porkActor + ", porkColor=" + porkColor + "]";
}
}
4)玩家
/*
* <pre>
* 文 件 名: PorkPlayer.java
* 描 述: <描述>
* 修改时间: 2014-6-15
* </pre>
*/
package com.dobuy.zhajinhua;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* <pre>
* 扑克牌玩家
*
* </pre>
*/
public class PorkPlayer implements Comparable<PorkPlayer>
{
private String allPorks;
/**
* 玩家有三张扑克牌
*/
private List<Pork> porks;
/**
* 三张扑克牌的类型:豹子、同花顺等
*/
private PorkType porkType;
/**
* 每个玩家默认有3张扑克牌 <默认构造函数>
*/
public PorkPlayer(String porksStr)
{
this.allPorks = porksStr;
init(porksStr);
}
/**
* 获取 allPorks
*
* @return 返回 allPorks
*/
public String getAllPorks()
{
return allPorks;
}
/**
* <pre>
* 根据发的3张牌计算出玩家的牌的类型
*
* @param porksStr
* </pre>
*/
private void init(String porksStr)
{
porks = new ArrayList<Pork>(3);
int index = 0;
int size = porksStr.length();
Pork pork = null;
while (index < size)
{
pork = new Pork(porksStr.substring(index, index + 2));
porks.add(pork);
index += 2;
}
// 对三张牌从小到大排序
Collections.sort(porks);
// 确定三张牌的类型
if (isBaozi())
{
porkType = PorkType.BAOZI;
}
else if (isTonghuashun())
{
porkType = PorkType.TONGHUASHUN;
}
else if (isShunzi())
{
porkType = PorkType.SHUNZI;
}
else if (isDuizi())
{
porkType = PorkType.DUIZI;
}
else
{
porkType = PorkType.SANPAI;
}
}
/**
* <pre>
* 判断是否是豹子(豹子要求3张牌面大小相同)
* @return
* </pre>
*/
private boolean isBaozi()
{
Pork pork = porks.get(0);
for (int i = 1, size = porks.size(); i < size; i++)
{
if (pork.getPorkActor() != porks.get(i).getPorkActor())
{
return false;
}
}
return true;
}
/**
* <pre>
* 判断是否是顺子
* @return
* </pre>
*/
private boolean isShunzi()
{
for (int i = 1, size = porks.size(); i < size; i++)
{
if (porks.get(i - 1).getPorkActor().compareTo(porks.get(i).getPorkActor()) != -1)
{
return false;
}
}
return true;
}
/**
* <pre>
* 判断是否是同花顺
*
* @return
* </pre>
*/
private boolean isTonghuashun()
{
if (!isShunzi())
{
return false;
}
Pork pork = porks.get(0);
for (int i = 1, size = porks.size(); i < size; i++)
{
if (pork.getPorkColor() != porks.get(i).getPorkColor())
{
return false;
}
}
return true;
}
/**
* <pre>
* 是否是对子
*
* @return
* </pre>
*/
private boolean isDuizi()
{
for (int i = 1, size = porks.size(); i < size; i++)
{
if (porks.get(i - 1).getPorkActor().compareTo(porks.get(i).getPorkActor()) == 0)
{
return true;
}
}
return false;
}
/**
* <pre>
* 获取扑克玩家手中的对子对应的扑克牌(不区分花色)
*
* @return
* </pre>
*/
private Pork getDuiziPork()
{
for (int i = 1, size = porks.size(); i < size; i++)
{
if (porks.get(i - 1).getPorkActor().compareTo(porks.get(i).getPorkActor()) == 0)
{
return porks.get(i);
}
}
return null;
}
/**
* <pre>
* 获取玩家手中非成对的那张牌
* @return
* </pre>
*/
private Pork getNoDuiziPork()
{
// 玩家只有3张牌,且是对子,而牌又是经过排序的,前2张相等,则最后一张是不成对的,否则后2张成对,第0张不同
if (porks.get(0).compareTo(porks.get(1)) == 0)
{
return porks.get(2);
}
else
{
return porks.get(0);
}
}
/**
* 获取 porkType
*
* @return 返回 porkType
*/
public PorkType getPorkType()
{
return porkType;
}
/**
* 重载方法
*
* @return
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((porkType == null) ? 0 : porkType.hashCode());
result = prime * result + ((porks == null) ? 0 : porks.hashCode());
return result;
}
/**
* 重载方法
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PorkPlayer other = (PorkPlayer)obj;
if (porkType != other.porkType)
return false;
if (porks == null)
{
if (other.porks != null)
return false;
}
else if (!porks.equals(other.porks))
return false;
return true;
}
/**
* 重载方法
*
* @return
*/
@Override
public String toString()
{
return "PorkPlayer [porks=" + porks + ", porkType=" + porkType + "]";
}
/**
* 重载方法
*
* @param o
* @return
*/
@Override
public int compareTo(PorkPlayer o)
{
int compare = getPorkType().compareTo(o.getPorkType());
// TODO
if (compare == 0)
{
switch (getPorkType())
{
/**
* 豹子、同花顺、顺子直接比较最大牌(最大牌会先比大小,再比花色)
*/
case BAOZI:
case TONGHUASHUN:
case SHUNZI:
{
return porks.get(2).compareTo(o.porks.get(2));
}
case DUIZI:
{
/**
* 对子比较
*/
Pork duizi1 = getDuiziPork();
Pork duizi2 = o.getDuiziPork();
// 先比较对子大小,对子大小相同时,比较散牌大小
if (duizi1.getPorkActor() == duizi2.getPorkActor())
{
compare = getNoDuiziPork().getPorkActor().compareTo(o.getNoDuiziPork().getPorkActor());
// 散牌大小相同时,比较对子中最大牌的花色
if (compare == 0)
{
return duizi1.getPorkColor().compareTo(duizi2.getPorkColor());
}
return compare;
}
else
{
// 对子大小不同时,直接比较对子大小
return duizi1.getPorkActor().compareTo(duizi2.getPorkActor());
}
}
case SANPAI:
{
// 散牌依次从最大数开始比较,只比较牌面值大小,如果相同,则从第二大值开始比较,直到不同或者全部比较完毕为止
for (int size = porks.size(), i = size - 1; i >= 0; i--)
{
compare = porks.get(i).getPorkActor().compareTo(o.porks.get(i).getPorkActor());
if (compare != 0)
{
return compare;
}
}
// 说明三张牌的牌面值全部相同,则比较最大牌的花色
return porks.get(2).getPorkColor().compareTo(o.porks.get(2).getPorkColor());
}
}
}
return compare;
}
}
5)单张扑克牌单元测试类
/*
* <pre>
* 文 件 名: PorkTest.java
* 描 述: <描述>
* 修改时间: 2014-6-15
* </pre>
*/
package com.dobuy.zhajinhua;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* <pre>
* <一句话功能简述>
*
* </pre>
*/
public class PorkTest
{
/**
* <pre>
* case 1:牌面大小不同时,比较牌面的大小
* </pre>
*/
@Test
public void test1()
{
Pork pork1 = new Pork("H5");
Pork pork2 = new Pork("X6");
assertTrue(pork1.compareTo(pork2) < 0);
}
/**
* <pre>
* case 1:牌面大小相同时,比较牌的花色
* </pre>
*/
@Test
public void test2()
{
Pork pork1 = new Pork("H5");
Pork pork2 = new Pork("X5");
assertTrue(pork1.compareTo(pork2) > 0);
}
}
6)玩家单元测试类
/*
* <pre>
* 文 件 名: PorkPlayerTest.java
* 描 述: <描述>
* 修改时间: 2014-6-16
* </pre>
*/
package com.dobuy.zhajinhua;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* <pre>
* <一句话功能简述>
*
* </pre>
*/
public class PorkPlayerTest
{
@Test
public void test1()
{
PorkPlayer player1 = new PorkPlayer("H2F2X2");
assertTrue(player1.getPorkType() == PorkType.BAOZI);
PorkPlayer player2 = new PorkPlayer("H2H3H4");
assertTrue(player2.getPorkType() == PorkType.TONGHUASHUN);
PorkPlayer player3 = new PorkPlayer("H2F3H4");
assertTrue(player3.getPorkType() == PorkType.SHUNZI);
PorkPlayer player4 = new PorkPlayer("H3F3H4");
assertTrue(player4.getPorkType() == PorkType.DUIZI);
PorkPlayer player5 = new PorkPlayer("H3F6H4");
assertTrue(player5.getPorkType() == PorkType.SANPAI);
}
@Test
public void test2()
{
/**
* case 1:都是豹子时,比较大小
*/
PorkPlayer player11 = new PorkPlayer("H2F2X2");
PorkPlayer player12 = new PorkPlayer("HAFAXA");
assertTrue(player11.compareTo(player12) < 0);
/**
* case 2:豹子大于同花顺
*/
PorkPlayer player21 = new PorkPlayer("H2F2X2");
PorkPlayer player22 = new PorkPlayer("H3H5H4");
assertTrue(player21.compareTo(player22) > 0);
/**
* case 3:都是同花顺时,比较大小
*/
PorkPlayer player31 = new PorkPlayer("H3H5H4");
PorkPlayer player32 = new PorkPlayer("F5F6F7");
assertTrue(player31.compareTo(player32) < 0);
/**
* case 4:同花顺大于顺子
*/
PorkPlayer player41 = new PorkPlayer("H3H5H4");
PorkPlayer player42 = new PorkPlayer("F5H6F7");
assertTrue(player41.compareTo(player42) > 0);
/**
* case 5:都是顺子时,比较最大牌(先比较最大牌的牌面值,相同则比较花色)
*/
PorkPlayer player51 = new PorkPlayer("H3X5H4");
PorkPlayer player52 = new PorkPlayer("F5H6F7");
assertTrue(player51.compareTo(player52) < 0);
/**
* case 6:顺子大于对子
*/
PorkPlayer player61 = new PorkPlayer("H3X5H4");
PorkPlayer player62 = new PorkPlayer("F5H7F7");
assertTrue(player61.compareTo(player62) > 0);
/**
* case 7.1:都是对子时,比较对子大小
*/
PorkPlayer player71 = new PorkPlayer("H3F5H5");
PorkPlayer player72 = new PorkPlayer("XAH6FA");
assertTrue(player71.compareTo(player72) < 0);
/**
* case 7.2:都是对子时,对子大小相同,比较散牌的大小
*/
PorkPlayer player73 = new PorkPlayer("HAF5MA");
PorkPlayer player74 = new PorkPlayer("XAH6FA");
assertTrue(player73.compareTo(player74) < 0);
/**
* case 7.3:都是对子时,比较大小(对子大小相同,比较散牌的大小)
*/
PorkPlayer player75 = new PorkPlayer("HAF5MA");
PorkPlayer player76 = new PorkPlayer("XAH6FA");
assertTrue(player75.compareTo(player76) < 0);
/**
* case 7.4:都是对子时,三张牌牌面值相同,比较对子中最大牌的花色
*/
PorkPlayer player77 = new PorkPlayer("HAX5MA");
PorkPlayer player78 = new PorkPlayer("XAM5FA");
assertTrue(player77.compareTo(player78) > 0);
/**
* case 8:对子大于散牌
*/
PorkPlayer player81 = new PorkPlayer("H3F5X3");
PorkPlayer player82 = new PorkPlayer("FQH9F7");
assertTrue(player81.compareTo(player82) > 0);
/**
* case 9.1:都是散牌时,比较最大牌的牌面值大小
*/
PorkPlayer player91 = new PorkPlayer("H3F5HJ");
PorkPlayer player92 = new PorkPlayer("X4H6FT");
assertTrue(player91.compareTo(player92) > 0);
/**
* case 9.2:都是散牌时,最大牌面值相同时,比较第2大牌的牌面值大小
*/
PorkPlayer player93 = new PorkPlayer("H3X5HJ");
PorkPlayer player94 = new PorkPlayer("X4M2FJ");
assertTrue(player93.compareTo(player94) > 0);
/**
* case 9.3:都是散牌时,最大、第2大牌面值相同时,比较最小牌的牌面值大小
*/
PorkPlayer player95 = new PorkPlayer("H3X5HJ");
PorkPlayer player96 = new PorkPlayer("X4M5FJ");
assertTrue(player95.compareTo(player96) < 0);
/**
* case 9.4:都是散牌时,三张牌的牌面值大小全部相同,则比较最大牌的花色
*/
PorkPlayer player97 = new PorkPlayer("H3X5HJ");
PorkPlayer player98 = new PorkPlayer("X3M5FJ");
assertTrue(player97.compareTo(player98) > 0);
}
}