一、思路分析
牌越大,价值就越大。
假设有下面一副牌,其中中间的数字是最好计算的,它们的价值就是本身的数字。
再往下,JQK
对应的价值是 11、12、13
。
左边的 A
对应的加载是 14
,2
对应的价值是 5
。
最后就是右边的两个王,小王所对应的是 16
,大王所对应的是 17
。
一旦牌有了价值后,我们就可以按照加载给它们进行排序。
二、基础代码
前面的准备牌、洗牌、发牌是一样的
public class App {
public static void main(String[] args) {
new PokerGame();
}
}
public class PokerGame {
//牌盒
static ArrayList<String> list = new ArrayList<>();
static {
//准备牌
String[] color = {"♦", "♣", "♥", "♠"};
String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
for (String c : color) {
for (String n : number) {
list.add(c + n);
}
}
list.add("小王");
list.add("大王");
}
public PokerGame() {
//洗牌
Collections.shuffle(list);
//发牌
ArrayList<String> lord = new ArrayList<>();
ArrayList<String> player1 = new ArrayList<>();
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
String poker = list.get(i);
//发底牌
if (i <= 2) {
lord.add(poker);
continue;
}
//给三个玩家轮流发牌
if (i % 3 == 0) {
player1.add(poker);
} else if (i % 3 == 1) {
player2.add(poker);
} else {
player3.add(poker);
}
}
}
}
三、指定牌的价值
由于我们是利用牌的价值给它进行排序的,所以首先第一步,需要先规定好牌的价值。
指定牌的价值的时候我们并没有在集合中添加 本身牌就是数字
的牌。
这是因为我们可以拿牌上的数字到Map集合中判断是否存在,存在,获取价值;不存在,本身的数字就是价值。
这样可以让集合存储的数据更少,查询的效率也更高一点。
//创建一个集合(键是牌上的数字,值是对应的加载),用来添加牌的价值
static HashMap<String, Integer> hm = new HashMap<>();
public PokerGame() {
//指定牌的价值
hm.put("J", 11);
hm.put("Q", 12);
hm.put("K", 13);
hm.put("A", 14);
hm.put("2", 15);
hm.put("小王", 50);
hm.put("大王", 100);
}
四、排序
这里我们额外写一个方法来进行排序。
在方法中,我们就可以使用 Collections
中的 sort()
来进行排序。
如果直接将 list
放进去的话,那么它采取的就是默认方式进行排序。
集合的泛型是 String
,因此默认就是按照 abcdefg
这种方式进行排序的,但是我们想要的是按照自己的牌指定的价值进行排序。
因此在参数二的位置就需要传入比较器对象,自己制定排序的规则。
我们可以简单来看一下 sort()
底层的源码,跟进看看。
可以发现在底层,它又去调用了 list
的 sort()
,并将比较器对象传递过去
![image-20240429143748192](https://img-blog.csdnimg.cn/img_convert/5a753e663511e4de690d36d16f7073d9.png)
选中 sort()
继续跟进,可以发现在方法的底层,它首先会把集合变成数组,然后再去调用 Arrays.sort()
。
Arrays.sort()
就是使用插入排序和二分查找两个结合的方式进行排序的。
![image-20240429143822120](https://img-blog.csdnimg.cn/img_convert/1af231f2c475b31ff584a97148ebac4b.png)
规则如下
负数:o1小 插入到前面
正数:o1大 插入到后面
0:o1的数字跟o2的数字是一样的,需要按照花色再次排序
代码示例
//利用牌的价值进行排序
//参数:集合
//♥5 ♥3 ♥6 ♥7 ♥9
public void order(ArrayList<String> list){
Collections.sort(list, new Comparator<String>() {
//Array.sort (插入排序 + 二分查找)
@Override
//o1:表示当前要插入到有序序列中的牌
//o2:表示已经在有序序列中存在的牌
public int compare(String o1, String o2) {
//1.计算o1的花色和价值 大王
String color1 = o1.substring(0, 1);
int value1 = getValue(o1);
//2.计算o2的花色和价值
String color2 = o2.substring(0, 1);
int value2 = getValue(o2);
//3.比较o1和o2的价值
int i = value1 - value2;
// 如果两张牌价值是一样的♥3 ♠3,那么就需要比较花色
return i == 0 ? color1.compareTo(color2) : i;
}
});
}
// 由于o1和o2的价值都需要进行计算,因此抽取成方法
//计算牌的价值
//参数:牌
//返回值:价值
public int getValue(String poker){// 例如:♥3
//获取牌上的数字
String number = poker.substring(1);//把这里截取出来的结果,让这个结果再Map集合中存在 “ 大王”
//拿着数字到map集合中判断是否存在
if(hm.containsKey(number)){
//存在,获取价值
return hm.get(number);
}else{
//不存在,类型转换
return Integer.parseInt(number);
}
}
排序
public PokerGame() {
//排序
order(lord);
order(player1);
order(player2);
order(player3);
}
此时会报错
这是因为在截取的时候
String color1 = o1.substring(0, 1); // 截出来的是:大 / 小
int value1 = getValue(o1); // 这里传递进去的就是:王
而且 王
在 集合
中并不存在,因此就会执行到 return Integer.parseInt(number);
,就会导致报错。
解决办法:在集合中添加牌的时候前面多一个空格就行了,这样就可以保证大小王跟上面牌的格式是一样的,将空格认为是大小王的花色。
list.add(" 小王");
list.add(" 大王");
五、完整代码
public class PokerGame {
//牌盒
static ArrayList<String> list = new ArrayList<>();
//创建一个集合,用来添加牌的价值
static HashMap<String, Integer> hm = new HashMap<>();
static {
//准备牌
String[] color = {"♦", "♣", "♥", "♠"};
String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
for (String c : color) {
for (String n : number) {
list.add(c + n);
}
}
list.add("小王");
list.add("大王");
//指定牌的价值
//牌上的数字到Map集合中判断是否存在
//存在,获取价值
//不存在,本身的数字就是价值
hm.put("J", 11);
hm.put("Q", 12);
hm.put("K", 13);
hm.put("A", 14);
hm.put("2", 15);
hm.put("小王", 50);
hm.put("大王", 100);
}
public PokerGame() {
//洗牌
Collections.shuffle(list);
//发牌
ArrayList<String> lord = new ArrayList<>();
ArrayList<String> player1 = new ArrayList<>();
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
String poker = list.get(i);
//发底牌
if (i <= 2) {
lord.add(poker);
continue;
}
//给三个玩家轮流发牌
if (i % 3 == 0) {
player1.add(poker);
} else if (i % 3 == 1) {
player2.add(poker);
} else {
player3.add(poker);
}
}
//排序
order(lord);
order(player1);
order(player2);
order(player3);
//看牌
lookPoker("底牌",lord);
lookPoker("钢脑壳",player1);
lookPoker("大帅比",player2);
lookPoker("蛋筒",player3);
}
/*
* 参数一:玩家的名字
* 参数二:每位玩家的牌
* */
public void lookPoker(String name, ArrayList<String> list){
System.out.print(name + ": ");
for (String poker : list) {
System.out.print(poker + " ");
}
System.out.println();
}
//利用牌的价值进行排序
//参数:集合
//♥5 ♥3 ♥6 ♥7 ♥9
public void order(ArrayList<String> list){
Collections.sort(list, new Comparator<String>() {
//Array.sort (插入排序 + 二分查找)
@Override
public int compare(String o1, String o2) {
//o1:表示当前要插入到有序序列中的牌
//o2:表示已经在有序序列中存在的牌
//负数:o1小 插入到前面
//正数:o1大 插入到后面
//0:o1的数字跟o2的数字是一样的,需要按照花色再次排序
//1.计算o1的花色和价值 大王
String color1 = o1.substring(0, 1);
int value1 = getValue(o1);
//2.计算o2的花色和价值
String color2 = o2.substring(0, 1);
int value2 = getValue(o2);
//3.比较o1和o2的价值 ♥3 ♠3
int i = value1 - value2;
return i == 0 ? color1.compareTo(color2) : i;
}
});
}
//计算牌的价值
//参数:牌
//返回值:价值
public int getValue(String poker){//♥3
//获取牌上的数字
String number = poker.substring(1);//把这里截取出来的结果,让这个结果再Map集合中存在 “ 大王”
//拿着数字到map集合中判断是否存在
if(hm.containsKey(number)){
//存在,获取价值
return hm.get(number);
}else{
//不存在,类型转换
return Integer.parseInt(number);
}
}
}