@[TOC](Java – 斗地主(后台版))
总纲
前期准备
- 创建程序启动入口
App
public class App {
public static void main(String[] args) {
/*
完成控制台的三步:
准备牌
发牌
洗牌
"♦", "♣", "♥", "♠"
"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"
*/
}
}
- 创建
PokerGame
类
public class PokerGame {
}
- 在
PokerGame
类中添加空参构造器
public class PokerGame {
public PokerGame() {
// 准备牌
// 洗牌
// 发牌
// 看牌
}
}
- 创建
App
中引用(创建)PokerGame
进入程序
// 进入程序
new PokerGame();
1.准备牌
1.1 准备牌思路
- 创建连个数组,分别存储花色和数字
- 创建一个集合,作为牌盒,后期会抽取为成员变量
- 遍历花色数组
- 遍历数字数组
- 将遍历获得的花色和数字拼接起来,添加到集合(牌盒)中
- 向牌盒中添加小王和大王
1.2 代码实现
- 准备一副牌,然后多次使用,此时可以用静态代码块进行编写.
静态代码块的特点: 随着类的加载而加载,并且只执行一次
static {
// 准备牌:
// 1.创建数组存储花色 "♦", "♣", "♥", "♠"
String[] color = {"♦", "♣", "♥", "♠"};
// 2.创建数组存储数字 "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"
String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
// 3.创建一个集合作为牌盒
ArrayList<String > list = new ArrayList<>();
// 4.循环花色数组,获取每一种花色
for (String c : color) {
// 5.循环数字数组,获取每一个数字
for (String n : number) {
// 6.将遍历获得的 花色 和 数字 拼接起来,并添加到集合中
list.add(c + n);
}
}
// 7.添加大小王
list.add("小王");
list.add("大王");
}
- 由于牌盒list需要在构造方法内使用,所以将list集合定义为成员变量
// 3.创建一个集合作为牌盒
// 添加static关键字,因为静态只能访问静态资源
static ArrayList<String > list = new ArrayList<>();
2.洗牌
2.1 思路
在构造方法中,直接使用Collections
工具类的shuffle方法即可
// 洗牌
Collections.shuffle(list);
System.out.println(list);
3.发牌
3.1 发牌思路
- 创建四个集合,分别存储 底牌 玩家1,玩家2,玩家3 的牌
- 遍历集合
- 将获取的前三张牌作为底牌,存储 底牌(lord) 中
- 将剩下的牌轮流发给三位玩家
3.2 代码实现
// 1.创建四个结合分别存储 底牌 ,玩家1,玩家2,玩家3
ArrayList<String> lord = new ArrayList<>();
ArrayList<String> player1 = new ArrayList<>();
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
// 2.遍历集合,获取每一张牌,将前三张作为底牌,后面的牌轮流发给三个玩家
// 2.1 遍历集合
for (int i = 0; i < list.size(); i++) {
String poker = list.get(i);
// 2.2 将前三张牌作为底牌存起来
if (i <= 2){
lord.add(poker);
continue;
}
// 2.3 将后面的牌轮流发给三个玩家
if (i % 3 == 0){ // 发给玩家1
player1.add(poker);
}else if (i % 3 == 1){ // 发给玩家2
player2.add(poker);
}else{ // 发给玩家3
player3.add(poker);
}
}
4.看牌(可省略 – 只做验证使用)
4.1 思路
定义一个方法,实现看牌功能
- 打印玩家名字
- 遍历集合,获取每一张牌
- 将每一张牌进行打印
- 打印一个回车换行
4.2 代码实现
- 定义方法
/**
* 看牌
* @param name 每位玩家的名字
* @param list 每一位玩家的牌
*/
private void lookPoker(String name, ArrayList<String> list) {
// 1.打印玩家名字
System.out.print(name + ": ");
// 2.遍历集合,拼接字符串
for (String poker : list) {
System.out.print(poker + " ");
}
System.out.println();
}
- 调用方法
// 看牌
lookPoker("底牌",lord);
lookPoker("玩家1",player1);
lookPoker("玩家2",player2);
lookPoker("玩家3",player3);
5.排序(两种方式)
5.1 第一种方式(利用序号进行排序)
5.1.1 分析
先把牌进行手动排列,再让排列后的牌和1,2,3…进行对应,对应的数字越大,牌也就越大.
5.1.2 思路
1.准备牌思路
- 创建Map集合,让序号和每一张牌产生联系
- 创建list集合,存储生成的序号
- 创建两个集合,分别存储 花色 和 数字
- 创建 初始序号
- 循环数字数组
- 循环花色数组
- 把获取到的 数字 和 花色 进行拼接,并添加到Map集合中
- 让序号自增
- 将序号添加到list集合中
- 添加小王,序号自增,再添加大王
2.洗牌思路
- 利用
Collections
工具类的shuffle方法进行洗牌
3.排序(发牌)思路
- 利用
TreeSet
集合进行优化,因为TreeSet
集合会进行自动排序 - 创建四个
TreeSet
集合 - 遍历list序号集合
- 向四个集合中添加元素
4.看牌思路
定义方法,实现看牌功能
1.创建 StringJoiner
对象,设置分隔符
2. 遍历list集合,通过键找值的方式,获取每一张牌的牌面
3. 将每一张面通过sj
对象进行拼接
4. 将获得牌面进行拼接
5.1.3 代码实现
1.前期准备
- 创建程序的启动入口
- 创建程序类
PokerGame
public class PokerGame {
// 牌盒 Map
static {
// 1.创建数组存储花色 "♦", "♣", "♥", "♠"
String[] color = {"♦", "♣", "♥", "♠"};
// 2.创建数组存储数字 "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"
String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
}
public PokerGame() {
}
}
2.准备牌
// 牌盒 Map
static HashMap<Integer, String> hm = new HashMap<>();
// 序号
static ArrayList<Integer> list = new ArrayList<>();
static {
// 1.创建数组存储花色 "♦", "♣", "♥", "♠"
String[] color = {"♦", "♣", "♥", "♠"};
// 2.创建数组存储数字 "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"
String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
// 3.定义一个变量,存储初始序号
int serialNumber = 1;
// 4.循环数字数组
for (String n : number) {
// 5.循环花色数组
for (String c : color) {
// 6.让序号和牌之间产生联系,并存入Map集合中
hm.put(serialNumber, c + n);
// 7.将序号存入list集合中,然后让序号自增
list.add(serialNumber);
serialNumber++;
}
}
// 8.将小王存入Map集合,将小王的序号添加到list集合中,让序号自增
hm.put(serialNumber,"小王");
list.add(serialNumber);
serialNumber++;
// 9.将小王存入Map集合,将小王的序号添加到list集合中
hm.put(serialNumber,"大王");
list.add(serialNumber);
3.洗牌
// 洗牌
Collections.shuffle(list);
4.排序(发牌)
// 发牌
// 1.创建四个TreeSet集合
TreeSet<Integer> lord = new TreeSet<>();
TreeSet<Integer> player1 = new TreeSet<>();
TreeSet<Integer> player2 = new TreeSet<>();
TreeSet<Integer> player3 = new TreeSet<>();
// 2.遍历list序号集合
for (int i = 0; i < list.size(); i++) {
// i : 表示元素的索引
// list.get(i) : 每一张牌的序号
Integer serialNumber = list.get(i);
// 3.向四个集合中添加元素
if (i <= 2){ // 地主
lord.add(serialNumber);
continue;
}
if (i % 3 == 0){ // 玩家1
player1.add(serialNumber);
}else if (i % 3 == 1){ // 玩家2
player2.add(serialNumber);
}else { // 玩家3
player3.add(serialNumber);
}
}
5.看牌
/**
* 看牌功能
*
* @param name 玩家的名字
* @param list 发到的牌
*/
private void lookCards(String name, TreeSet<Integer> list) {
// 1.遍历集合,获取每一张的序号,通过键找值的方式获取对应的牌面
StringJoiner sj = new StringJoiner(", ", "", "");
// 1.1 遍历集合,获取每一张的序号
for (Integer number : list) {
// 1.2 通过键找值的方式获取对应的牌面,并进行拼接
String poker = hm.get(number);
sj.add(poker);
}
// 2.拼接成字符串进行打印
System.out.println(name + " : " + sj);
}
- 调用看牌功能
// 看牌
lookCards("地主", lord);
lookCards("玩家1", player1);
lookCards("玩家2", player2);
lookCards("玩家3", player3);
5.2 第二种方式(给每张牌计算价值)
5.2.1 分析
5.2.2 思路
1.排序思路
- 在成员位置创建一个
HashMap
集合,作为牌的价值容器 - 在静态代码块中为每张牌添加对应的价值
- 定义一个方法,对发牌进行排序
- 使用list集合调用sort方法进行排序
- 使用的是添加排序器(
Comparator
)的方式 - 在排序器中指定比较规则
- 先取出两张牌的花色
- 再定义一个方法去获取每张牌的价值
- 比较规则为: 如果价值相同,就去比较花色的值
- 在定义的
getValue
方法中,对传递过来的poker
进行截取
- 截取方式为: 从索引为1的字符开始截取,直到末尾
- 对截取的数字进行判断,判断其是否存在于
hm
集合中 - 如果存在,则从集合中取出价值进行返回
- 如果不存在,则将其本身作为价值进行返回
- 注意: 由于是从索引1开始截取,而牌盒中有两张特殊的牌,大王和小王,如果按照原来添加的字符串进行截取,则会截取到字符 “王”.而我们在存储每张牌的价值的时候,并没有存储字符"王",我们存储的是"大王"和"小王".此时,我们采取的解决方案是:**在添加价值的时候,在字符串"大王"和"小王"的时候,在两个字符串前面添加一个空格,添加完成后的字符串为 " 小王" 和 " 大王".**到此,此问题得以解决.
5.2.3 代码实现
1.前期准备
- 程序入口
APP
- 准备牌,洗牌,发牌
public class PokerGame {
// 3.创建一个集合作为牌盒
// 添加static关键字,因为静态只能访问静态资源
static ArrayList<String > list = new ArrayList<>();
// 准备牌
// 静态代码块:
// 特点: 随着类的加载而加载,并且只执行一次
static {
// 准备牌:
// 1.创建数组存储花色 "♦", "♣", "♥", "♠"
String[] color = {"♦", "♣", "♥", "♠"};
// 2.创建数组存储数字 "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"
String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
// 4.循环花色数组,获取每一种花色
for (String c : color) {
// 5.循环数字数组,获取每一个数字
for (String n : number) {
// 6.将遍历获得的 花色 和 数字 拼接起来,并添加到集合中
list.add(c + n);
}
}
// 7.添加大小王
list.add("小王");
list.add("大王");
}
public PokerGame() {
// 洗牌
Collections.shuffle(list);
System.out.println(list);
// 发牌
// 1.创建四个结合分别存储 底牌 ,玩家1,玩家2,玩家3
ArrayList<String> lord = new ArrayList<>();
ArrayList<String> player1 = new ArrayList<>();
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
// 2.遍历集合,获取每一张牌,将前三张作为底牌,后面的牌轮流发给三个玩家
// 2.1 遍历集合
for (int i = 0; i < list.size(); i++) {
String poker = list.get(i);
// 2.2 将前三张牌作为底牌存起来
if (i <= 2){
lord.add(poker);
continue;
}
// 2.3 将后面的牌轮流发给三个玩家
if (i % 3 == 0){ // 发给玩家1
player1.add(poker);
}else if (i % 3 == 1){ // 发给玩家2
player2.add(poker);
}else{ // 发给玩家3
player3.add(poker);
}
}
}
}
2.指定牌的价值
- 在
PokerGame
中添加成员变量hm
,用于添加牌的价值
//创建一个集合,用来添加牌的价值
static HashMap<String, Integer> hm = new HashMap<>();
- 在静态代码块中添加牌的价值
//指定牌的价值
//牌上的数字到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);
3.排序(Order
)
/**
* 定义方法,完成排序功能
*
* @param list 发给玩家的牌的集合
*/
private void order(ArrayList<String> list) {
// 1.使用Collections工具类调用sort方法,并指定排序规则
// 1.1 调用sort方法
// sort 的底层采用的是 二分查找 和 插入排序 的方式进行排序的
Collections.sort(list, new Comparator<String>() {
@Override
// o1 : 表示要插入到前面有序序列里面的牌
// o2 : 已存在的有序序列中的牌
// 正数 : o1大 插入到后面
// 负数 : o1小 插入到前面
// 0 : o1跟o2的价值是一样的,需要再根据花色进行排序
public int compare(String o1, String o2) {
// 1.2 指定排序规则
// 1.2.1 获取花色
String color1 = o1.substring(0, 1);
String color2 = o2.substring(0, 1);
// 1.2.2 获取价值,定义方法
int value1 = getValue(o1);
int value2 = getValue(o2);
// 指定排序规则
int i = value1 - value2;
return i == 0 ? color1.compareTo(color2) : i;
}
});
}
4.获取价值方法(getValue
)
/**
* 获取每张牌的价值
*
* @param poker 牌
* @return 价值
*/
public int getValue(String poker) {
// 1.从索引1开始截取字符串
String number = poker.substring(1);
// 2.通过截取的字符串进行判断,判断截取的字符串是否存在于hm集合中
if (hm.containsKey(number)) {
// 2.1 如果存在,则需要从集合中取出对应的价值,进行返回
return hm.get(number);
} else {
// 2.2 如果不存在,则直接把截取的字符串本身作为价值进行返回,但需要进行强制转换
return Integer.parseInt(number);
}
}
6.面向对象的设计