用扑克游戏操练List常用方法

线性表

List(线性表)是一个接口,ArrayList(顺序表)和LinkedList(链表)继承了List。

List的常用方法:

方法签名 功能描述
add(E e) 把e这个元素,尾插到线性表中
add(int index,E e) 把e这个元素,插入到index所在位置,同时,index之后的所有元素,必须"逻辑"后移
remove(int index) 删除index这个下标的元素,同时,index之后的所有元素,必须"逻辑"前移
remove(Object o) 删除第一个遇到的o元素(本质上是使用"equals"进行比较)
get(int index) 返回index下标处的元素
set(int index,E e) 用e替换index下标处的元素
size() 元素个数
clear() 清空线性表
isEmpty() 判断是否为一个空的线性表
contains(Object o) 返回线性表中,是否包含o这个对象(本质上使用的是"equals"方法)
indexOf(Object o) 返回线性表中,第一个遇到o这个对象的下标(equals)
lastIndexOf(Object o) 返回线性表中,最后一个遇到o这个对象的下标(equals)
subList(int from,int to) 从线性表中,截取一段线性表下来,[from,to)不会影响原线性表
sort(Comparator cmp) 对线性表进行排序,以传入的比较器进行元素的比较
iterator() 返回迭代器,进行从前向后遍历
listIterator() 效果等同于listInterator(0)
listIterator(int index) 从index位置开始遍历
toArray() List转成数组

ArrayList(顺序表):

方法 解释
ArrayList() 无参构造
ArrayList(Collection c) 利用其它Collection构建ArrayList
ArrayList(int initialCapacity) 指定顺序表初始容量

LinkedList(链表):

方法 解释
LinkedList() 无参构造

不管是List、ArrayList还是LinkedList都涉及到泛型,需要什么类型的线性表就在泛型里填什么就好了,注意基本类型必须全部用包装类。接下来我们来玩会扑克牌。

游戏一:一副扑克牌(只要各花色从1到5的牌)

  1. 洗牌
  2. 给5名玩家,各发两张牌
  3. 依次展示5名玩家手中的牌

分析:

  1. 需要扑克牌类来定义每一张牌
  2. 需要List<扑克牌> 牌组 = new ArrayList<>();
  3. 需要玩家类,玩家类中包含List<扑克牌> 手牌
  4. 将牌组的牌分发给个玩家手中

扑克牌类:

public class Card {
     
    public String suit;//花色
    public int rank;//牌面值

    public Card(String suit,int rank){
     
        this.suit = suit;
        this.rank = rank;
    }

    @Override
    //打印这张牌
    public String toString() {
     
        return String.format("[%s %d]",suit,rank);
    }
}

玩家类:

import java.util.ArrayList;
import java.util.List;

public class Player {
     
    public List<Card> cards = new ArrayList<>();//手牌
    public String name;//玩家姓名

    public Player(String name) {
     
        this.name = name;
    }
}

玩游戏:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Game {
     
    //制作扑克牌(初始化)
    private static void initializeCards(List<Card> cards){
     
        for(String suit: new String[]{
     "♠","♥","♦","♣"}){
     
            for(int rank = 1;rank <= 5;rank++){
     
                Card card = new Card(suit,rank);
                //把扑克牌放入牌组中
                cards.add(card);
            }
        }
    }

    public static void main(String[] args) {
     
        //5名玩家,用List将其保存起来
        List<Player> playerList = new ArrayList<>();
        playerList.add(new Player("周润发"));
        playerList.add(new Player("刘德华"));
        playerList.add(new Player("周星驰"));
        playerList.add(new Player("高进"));
        playerList.add(new Player("未知用户"));

        //牌组容器
        List<Card> cardList = new ArrayList<>();

        //初始化扑克牌
        initializeCards(cardList);
        System.out.println("初始化好的牌:");
        System.out.println(cardList);

        //洗牌,可以直接调用Collections.shuffle来洗牌
        Collections.shuffle(cardList);
        System.out.println("洗牌之后,抽排之前:");
        System.out.println(cardList);

        //发牌
        int n = 2;//每名玩家发几张牌
        for(int i = 0; i < n;i++){
       //一共发2轮牌
            for(Player plaryer:playerList){
      //每名玩家依次抽排
                //从牌组中,抽一张牌出来
                Card card = cardList.remove(0);
                //把这张牌放到玩家的手牌中
                plaryer.cards.add(card);
            }
        }

        for(Player player:playerList){
     
            System.out.printf("玩家[%s]的手牌是:%s%n",player.name,player.cards);
        }

        System.out.println("抽完牌之后,牌组中还有的牌:");
        System.out.println(cardList);
    }
}

运行结果:

用扑克游戏操练List常用方法_第1张图片

游戏二:

  1. 将游戏一中的20张牌全部发给玩家(每人4张)
  2. 若哪名玩家获得黑桃1,则该玩家获胜

分析:

  1. 既然需要将牌全部发完,那么就是将刚才的发牌轮数n改成5即可。
  2. 发完牌之后,拿每一张牌和要寻找的牌做对比,相同则该玩家获胜

分析1只是改个数字所以不写了,这里写一下分析2,首先不管怎么做,我们都需要对牌进行对比,所以免不了要给card类写equals方法。

@Override
    public boolean equals(Object o) {
     
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Card card = (Card) o;
        return rank == card.rank && Objects.equals(suit, card.suit);
    }

做法一:直接使用equals依次比较

        //先定义一张需要对比的牌黑桃1
        Card toFoundCard = new Card("♠",1);
        for(Player player : playerList){
     
            for(Card card:player.cards){
     
                if(toFoundCard.equals(card)){
     
                    System.out.println(player.name+"获胜");
                    return;
                }
            }
        }

做法二:使用List的indexOf方法对比,如果不等于-1则说明找到了,注:indexOf本质上也是使用equals方法

        Card toFoundCard = new Card("♠",1);
        for (Player player : playerList) {
     
            if(player.cards.indexOf(toFoundCard) != -1){
     
                System.out.println(player.name+"获胜");
            }
        }

做法三:使用contains方法,true说明找到,false说明没有找到,同样的本质上应用equals方法

        for (Player player : playerList) {
     
            if(player.cards.contains(toFoundCard)){
     
                System.out.println(player.name+"获胜");
            }
        }

运行结果:

用扑克游戏操练List常用方法_第2张图片

游戏三:

  1. 每名玩家依次随机抽取下家一张手牌
  2. 抽取结束后,手牌中有黑桃1的玩家获胜

分析:

  1. 依次抽取,则需遍历玩家线性表(playerList)
  2. 当前玩家抽取其下家手牌,则需记录当前玩家和下家
  3. 如果玩家是playerList中的最后一个,则其下家是第一个玩家
  4. 随机抽取,需要Random来生成抽取下标
  5. 判断获胜之前写过了所以直接拿来用就好了
        Random random = new Random();
        //开始抽牌,每名玩家依次抽取下家一张随机的手牌
        for(int i = 0; i < playerList.size();i++){
     
            //当前玩家
            Player currentPlayer = playerList.get(i);
            //下家
            //playerList中的最后一名玩家需要抽第一个玩家的手牌,所以得判断是否为最后一个玩家
            Player nextPlayer = playerList.get(i != playerList.size() - 1 ? i + 1 : 0);

            //要取的牌的下标,随机生成
            int toDrawIndex = random.nextInt(nextPlayer.cards.size());
            //取牌
            Card drawCard = nextPlayer.cards.remove(toDrawIndex);
            //放入当前玩家手中
            currentPlayer.cards.add(drawCard);
        }

运行结果:

用扑克游戏操练List常用方法_第3张图片

游戏四:

  1. 发哥是赌神,具有变牌能力,如果他手上没有黑桃1,就可以把手里面的第一张牌变成黑桃1
  2. 交换牌之前,有机会变一次,交换牌之后,有机会变一次

分析:

  1. 周润发先得判断自己手里有没有黑桃1,有则发功。
  2. 如果没有,则需要遍历寻找哪个玩家的哪张手牌是黑桃1
  3. 完成交换
  4. 两次变牌其实都是一样的过程,大家做的时候可以抽象成方法
        Player faGe = playerList.get(0);
        if(!faGe.cards.contains(toFoundCard)){
     
            //发哥手里没有黑桃1,需要发功(交换),先把第一张牌拿出来
            //发哥手里的第一张牌
            Card firstCard = faGe.cards.get(0);
            //然后将发哥的第一个牌换成黑桃1
            faGe.cards.set(0,toFoundCard);
            for(int i = 1; i < playerList.size();i++){
     
                //需要知道哪个玩家手里拿黑桃1了,并且记录下标
                int index1 = -1;
                if((index1 = playerList.get(i).cards.indexOf(toFoundCard)) != -1){
     
                    //把手持黑桃1的玩家手中的黑桃1换成发哥的第一张牌
                    playerList.get(i).cards.set(index1, firstCard);
                }
            }
        }

运行结果:

用扑克游戏操练List常用方法_第4张图片

注:前面的游戏都是扩展,所以只写了最重要的部分,其实重点是为了熟练应用常用方法,下面我们再来写一个完整的游戏,我们俗称抽王八,这里我们叫捉鬼。

游戏五:捉鬼

规则:还是这二十张牌,去掉一张1,五个人依次抓牌,直到把所有的牌都抓光。抓牌期间,一旦出现两张牌点数相同就可以扔掉。所有人将手里的牌整理好之后,开始依次抽取下家手中的一张牌,凑成对就扔掉。一直进行,若玩家手中没有牌了,则退出游戏,直到剩下最后一个玩家,则该玩家被捉。

分析:

  1. 发牌的时候,玩家自动将自己手中配对的牌直接舍弃。
  2. 发牌结束后,手中没牌的玩家直接退出即可。
  3. 抽牌过程还是跟之前的整体思路相同,不过得注意抽完下家的牌时,如果下家手中没有牌了,那他就退出游戏。与此同时,当前玩家得判断自己抽完牌之后有没有配对,配对则舍弃,并且还要判断手中是否有牌,没牌则退出

Card类:

注意:我们需要再写一个equalsRank方法,来判断是否配对了(点数相同即配对)

import java.util.Objects;

public class Card {
     
    public String suit;//花色
    public int rank;//牌面值

    public Card(String suit,int rank){
     
        this.suit = suit;
        this.rank = rank;
    }

    @Override
    //打印这张牌
    public String toString() {
     
        return String.format("[%s %d]",suit,rank);
    }

    @Override
    public boolean equals(Object o) {
     
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Card card = (Card) o;
        return rank == card.rank && Objects.equals(suit, card.suit);
    }

    //再写一个equals方法,使得只要点数相同即为true
    public boolean equalsRank(Card card){
     
        return rank == card.rank;
    }
}

Player类:

注:重写toString方法,利于观察游戏过程,调试bug。

import java.util.ArrayList;
import java.util.List;

public class Player {
     
    public List<Card> cards = new ArrayList<>();//手牌
    public String name;//玩家姓名

    public Player(String name) {
     
        this.name = name;
    }

    @Override
    public String toString() {
     
        return "Player{" +
                "cards=" + cards +
                ", name='" + name + '\'' +
                '}';
    }
}

Game类:

import java.util.*;

public class Game {
     
    //玩家初始化
    private static List<Player> initializePlayerList() {
     
        List<Player> playerList = new ArrayList<>();
        playerList.add(new Player("周润发"));
        playerList.add(new Player("刘德华"));
        playerList.add(new Player("周星驰"));
        playerList.add(new Player("高进"));
        playerList.add(new Player("未知用户"));
        return playerList;
    }

    //扑克牌初始化,并直接删掉黑桃1
    private static List<Card> initializeCardList() {
     
        List<Card> cardList = new ArrayList<>();
        for(String suit:new String[]{
     "♠","♥","♦","♣"}){
     
            for(int rank = 1; rank <= 5;rank++){
     
                cardList.add(new Card(suit,rank));
            }
        }

        //删掉黑桃1
        cardList.remove(0);
        return cardList;
    }

    //将打印手牌抽象成方法,方便多次使用
    private static void printHands(List<Player> playerList){
     
        for (Player player : playerList) {
     
            System.out.printf("%s 的手牌:%s%n",player.name,player.cards);
        }
    }

    //将发牌抽象成方法,玩家摸牌过程中自动检查是否配对,配对则扔掉
    private static void drawCard(List<Player> playerList, List<Card> cardList) {
     
        //只要cardList中还有牌就继续抽
        while(true) {
     
            for (Player player : playerList) {
     
                //if(cardList.size() == 0){//两种方式都可以
                //注意,这里特意将if判断写在for循环里面,
                // 这样可以达到每个玩家都可以判断是否还有牌
                if(cardList.isEmpty()){
     
                    return;
                }
                Card card = cardList.remove(0);
                boolean flag = true;
                //练一下迭代器,判断抽上来的牌和手牌是否配对
                Iterator<Card> it = player.cards.iterator();
                while(it.hasNext()){
     
                    Card everyCard = it.next();
                    if(everyCard.equalsRank(card)){
     
                        it.remove();
                        flag = false;
                        break;
                    }
                }
                //没有配对成功,则插入
                if(flag){
     
                    player.cards.add(card);
                }
            }
        }
    }

    public static void main(String[] args) {
     
        List<Player> playerList = initializePlayerList();
        List<Card> cardList = initializeCardList();
        Collections.shuffle(cardList);

        //发牌
        drawCard(playerList,cardList);
        //打印发牌结束之后每个玩家手中的牌
        printHands(playerList);

        //把没有手牌的玩家去掉
        Iterator<Player> iterator = playerList.iterator();
        while(iterator.hasNext()){
     
            Player next = iterator.next();
            if(next.cards.isEmpty()){
     
                iterator.remove();
            }
        }

        //开始游戏
        //只剩一名玩家的时候就结束
        Random random = new Random();
        while(playerList.size() != 1){
     
            for(int i = 0;i < playerList.size();i++){
     
                //多判断一次是防止出现最后一名玩家自己抽自己的情况。
                if(playerList.size() == 1) break;

                System.out.println("目前在游戏中的玩家有:");
                printHands(playerList);

                //获得当前玩家
                Player current = playerList.get(i);
                int nextIndex = i == playerList.size()-1 ? 0 : i+1;
                //获得下家
                Player next = playerList.get(nextIndex);
                //current随机抽取next的一张手牌
                int randomIndex = random.nextInt(next.cards.size());
                //先把牌抽出来
                Card card = next.cards.remove(randomIndex);

                System.out.println(current.name+"抽了"+next.name+"一张"+card);
                //如果下家的手牌为空了,下家退出
                if(next.cards.isEmpty()){
     
                    playerList.remove(nextIndex);
                }

                //判断抽出来的牌有没有和手牌中一样的,如果有就去掉。
                boolean flag = true;
                Iterator<Card> it2 = current.cards.iterator();
                while(it2.hasNext()){
     
                    if(it2.next().equalsRank(card)){
     
                        it2.remove();
                        flag = false;
                        break;
                    }
                }
                if(flag){
     
                    current.cards.add(card);
                }
                //如果当前玩家手中没有牌则退出游戏
                if(current.cards.isEmpty()){
     
                    playerList.remove(i);
                    i = i - 1;
                }
            }
        }
        System.out.println(playerList.get(0).name + "被捉了");
    }
}

你可能感兴趣的:(数据结构,游戏,数据结构,arraylist)