Skip to content

值得您信賴的旅遊品牌 | 團體旅遊、自由行的專家‎

機場接送

Menu
  • 首頁
  • 旅遊天地
  • 裝潢設計
  • 環保清潔
  • 發燒車訊
Menu

用斗地主的實例學會使用java Collections工具類

Posted on 2021-03-172021-03-17 by admin

目錄

  • 一、背景
  • 二、概念
    • 1、定義
    • 2、方法
      • 2.1、排序方法
      • 2.2、查找/替換方法
  • 三、斗地主實例
    • 3.1、代碼結構
    • 3.2、常量定義
    • 3.3、單隻牌類
    • 3.4、玩家類
    • 3.5、主程序
  • 四、深入理解

一、背景

最近在學習數據結構和算法的過程中頻繁用到了Collections工具類,這是開發中的一把利器,簡化了許多涉及集合的編碼,該文將通過實例對此工具類進入深入剖析。

二、概念

1、定義

java.util.Collections
是一個包裝類。它包含有各種有關集合操作的靜態多態方法。此類不能實例化,就像一個工具類,服務於Java的集合框架。

public class Collections {
    // 默認構造方法私有化,不允許實例化.
    private Collections() {
    }
    ...
}
2、方法

Collections的方法都為靜態方法,主要分為以下幾類:該文主要對排序、查找/替換等方法進行解析。

2.1、排序方法
  • 方法定義:
// 反轉
public static void reverse(List<?> list)
// 隨機排序
public static void shuffle(List<?> list) 
// 按自然排序的升序排序
 public static <T> void sort(List<T> list, Comparator<? super T> c)
// 交換兩個索引位置的元素
public static void swap(List<?> list, int i, int j)
// 旋轉
public static void rotate(List<?> list, int distance)
2.2、查找/替換方法
// 二分查找
int binarySearch(List<? extends Comparable<? super T>> list, T key)
// 根據定製排序,返回最大元素
int max(Collection coll, Comparator c)
// 根據定製排序,返回最小元素
int min(Collection coll, Comparator c)
// 統計元素出現次數
int frequency(Collection c, Object o),統計元素出現次數
// 統計targe在list中第一次出現的索引
int indexOfSubList(List list, List target)
// 用新元素替換舊元素
boolean replaceAll(List list, Object oldVal, Object newVal)

三、斗地主實例

3.1、代碼結構

3.2、常量定義
  • 用集合的方式定義撲克牌的花色、牌面数字、大小王。
/**
 * 撲克牌常量定義
 *  * @author zhuhuix
 * @date 2020-06-05
 */
public class Constant {

    // 紙牌花色:黑桃,紅心,梅花,方塊
    final static List<String> COLORS = new ArrayList<>(
            Arrays.asList(new String[]{"", "", "", ""}));
    // 牌面数字
    final static List<String> NUMBERS = new ArrayList<>(
            Arrays.asList(new String[]{"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"}));
    // 大王小王
    final static List<String> JOKER = new ArrayList<>(
            Arrays.asList(new String[]{"小王","大王"}));
}
3.3、單隻牌類
  • 在單隻牌類的定義中,重寫了會影響到牌面大小的compareTo比較方法:
    — 如果是”王“的兩隻牌的比較,則”大王“大於”小王“;
    — 如果是”王“與“数字牌”之間的比較,則”王“大於“数字牌”;
    — 如果是“数字牌”相互之間的比較,数字大的牌則牌面大,如果数字相同,則按花色比較(<< < )(雖然斗地主不按花色排列大小,但程序會按花色大小進行理牌)。
/**
 * 單隻牌
 *  * @author zhuhuix
 * @date 2020-06-05
 */
public class Card implements Comparable {

    // 花色
    private String color = "";
    //数字
    private String number = "";

    public Card() {
    }

    public Card(String color, String number) {
        this.color = color;
        this.number = number;
    }

    public String getColor() {
        return this.color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getNumber() {
        return this.number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return this.color + this.number;
    }

    @Override
    public int compareTo(Object o) {
        if (o instanceof Card) {
            int thisColorIndex = Constant.COLORS.indexOf(this.getColor());
            int anotherColorIndex = Constant.COLORS.indexOf(((Card) o).getColor());
            int thisNumberIndex = Constant.NUMBERS.indexOf(this.getNumber());
            int anotherNumberIndex = Constant.NUMBERS.indexOf(((Card) o).getNumber());

            // 大小王之間相互比較: 大王大於小王
            if ("JOKER".equals(this.color) && "JOKER".equals(((Card) o).getColor())) {
                    return thisColorIndex > anotherColorIndex ? 1 : -1;
            }

            // 大小王與数字牌之間相互比較:大小王大於数字牌
            if ("JOKER".equals(this.color) && !"JOKER".equals(((Card) o).getColor())) {
                return 1;
            }
            if (!"JOKER".equals(this.color) && "JOKER".equals(((Card) o).getColor())) {
                return -1;
            }

            // 数字牌之間相互比較: 数字不相等,数字大則牌面大;数字相等 ,花色大則牌面大
            if (thisNumberIndex == anotherNumberIndex) {
                return thisColorIndex > anotherColorIndex ? 1 : -1;
            } else {
                return thisNumberIndex > anotherNumberIndex ? 1 : -1;
            }

        } else {
            return -1;
        }
    }
}
3.4、玩家類
  • 玩家類中主要定義了抓牌、洗牌、理牌、找牌、獲取最大最小牌、統計炸彈數等成員方法,在這些成員方法中,我們廣泛應用了Collections工具類的靜態方法。
/**
 1. 玩家
 2.  * @author zhuhuix
 3. @date 2020-06-05
 */
public class Player {

    // 玩家姓名
    private String name;

    // 玩家類型:农民/地主
    private String type;

    // 抓到的牌
    private List<Card> cards;

    public Player(String name, String type) {
        this.name = name;
        this.type = type;
        this.cards = new ArrayList<>();
    }

    // 洗牌 shuffle
    public void shuffle() {
        Collections.shuffle(this.cards);
    }

    // 理牌 sort
    public void sort() {
        Collections.sort(this.cards, Card::compareTo);
    }

    // 抓牌
    public void draw(Card card) {
        this.cards.add(card);
    }

    // 出牌
    public void play(Card card) {
        this.cards.remove(card);
    }

    // 找出最大牌 max
    public Card max() {
        return Collections.max(this.cards, Card::compareTo);
    }

    // 找出最小牌 min
    public Card min() {
        return Collections.min(this.cards, Card::compareTo);
    }

    // 找到指定牌的位置 binarySearch
    public int binarySearch(Card card) {
        return Collections.binarySearch(this.cards, card, Card::compareTo);
    }

    // 統計有幾手炸彈 frequency
    public int frequency() {
        int count = 0;
        List<String> numbers= new ArrayList<>();
        List<String> colors= new ArrayList<>();
        for (int i = 0; i < this.cards.size(); i++) {
            colors.add(this.cards.get(i).getColor());
            numbers.add(this.cards.get(i).getNumber());
        }
        for (int j = 0; j < Constant.NUMBERS.size(); j++) {
            if (Collections.frequency(numbers, Constant.NUMBERS.get(j)) == 4) {
                count++;
            }
        }
        if (Collections.frequency(colors, "JOKER") == 2) {
            count++;
        }
        return count;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public List<Card> getCards() {
        return cards;
    }

    public void setCards(List<Card> cards) {
        this.cards = cards;
    }

    @Override
    public String toString() {
        StringBuilder poker = new StringBuilder("[");
        Iterator<Card> iterator = this.cards.iterator();
        while (iterator.hasNext()) {
            poker.append(iterator.next().toString() + ",");
        }
        poker.setCharAt(poker.length() - 1, ']');
        return this.getType() + ":" + this.getName() + "拿到" + this.cards.size() + "張牌:" + poker;
    }
3.5、主程序
  1. 生成一整副牌;
  2. 設置3個玩家,其中兩個為农民,一個為地主;
  3. 3人輪流抓牌,地主多拿三張牌;
  4. 玩家理牌看牌(找到最大牌最小牌);
  5. 判斷大王是否在地主手上?
  6. 統計各個玩家手上有幾個炸彈?
/**
 * 斗地主的主程序
 *
 * @author zhuhuix
 * @date 2020-6-5
 */
public class PlayDemo {

    public static void main(String[] args) {

        // 生成一副撲克牌
        Poker poker = new Poker();
        System.out.println("撲克牌共" + poker.getCardCount() + "只");

        // 設置三個玩家,並設定兩人為农民,一個為地主
        int playCount = 3;
        Player player1 = new Player("玩家1", "农民");
        Player player2 = new Player("玩家2", "农民");
        Player player3 = new Player("玩家3", "地主");

        // 三個玩家按順序抓牌
        int i;
        for (i = 0; i < poker.getCardCount() - playCount; i++) {
            if (i % playCount == 0) {
                player1.draw(poker.getCards().get(i));
            } else if (i % playCount == 1) {
                player2.draw(poker.getCards().get(i));
            } else if (i % playCount == 2) {
                player3.draw(poker.getCards().get(i));
            }
        }

        // 地主拿剩餘底牌
        while (i < poker.getCardCount()) {
            player3.draw(poker.getCards().get(i));
            i++;
        }

        // 展示三個玩家洗牌後手上的牌面及最大和最小的牌
        player1.sort();
        System.out.println(player1.toString());
        System.out.println("最大牌是:"+player1.max().toString()+",最小牌是:"+player1.min().toString());
        player2.sort();
        System.out.println(player2.toString());
        System.out.println("最大牌是:"+player2.max().toString()+",最小牌是:"+player2.min().toString());
        player3.sort();
        System.out.println(player3.toString());
        System.out.println("最大牌是:"+player3.max().toString()+",最小牌是:"+player3.min().toString());

        // 大王是否在地主手裡
        if (player3.binarySearch(new Card("JOKER","大王"))>=0){
            System.out.println("大王在"+player3.getType()+player3.getName()+"手裡");
        }

        // 統計有幾手炸彈
        System.out.println(player1.getName()+"手上有"+player1.frequency()+"手炸彈");
        System.out.println(player2.getName()+"手上有"+player2.frequency()+"手炸彈");
        System.out.println(player3.getName()+"手上有"+player2.frequency()+"手炸彈");
    }
}

程序輸出如下:

四、深入理解

  • 我們對其中的一些方法進行源碼跟蹤
    — shuffle
 public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=size; i>1; i--)
                swap(list, i-1, rnd.nextInt(i));
        } else {
        	//將集合轉化成數組
            Object arr[] = list.toArray();

            //  通過隨機數隨機交換數組元素位置
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextInt(i));
			// 通過迭代器將打亂順序的數組賦值給集合
            ListIterator it = list.listIterator();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);
            }
        }
    }

— sort

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
}
    ...
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        //調用數組工具類的排序方法--該方法為改進過的歸併排序
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

— min/max

public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
        if (comp==null)
            return (T)min((Collection) coll);

        Iterator<? extends T> i = coll.iterator();
        T candidate = i.next();
		// 通過迭代器循環比較,找到最小的
        while (i.hasNext()) {
            T next = i.next();
            if (comp.compare(next, candidate) < 0)
                candidate = next;
        }
        return candidate;
 }
 
public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) {
        if (comp==null)
            return (T)max((Collection) coll);

        Iterator<? extends T> i = coll.iterator();
        T candidate = i.next();
		// 通過迭代器循環比較,找到最大的
        while (i.hasNext()) {
            T next = i.next();
            if (comp.compare(next, candidate) > 0)
                candidate = next;
        }
        return candidate;
}

— binarySearch

public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) {
        if (c==null)
            return binarySearch((List<? extends Comparable<? super T>>) list, key);

        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key, c);
        else
            return Collections.iteratorBinarySearch(list, key, c);
    }
    ...
    // 二分查找法
    private static <T> int iteratorBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
        int low = 0;
        int high = l.size()-1;
        ListIterator<? extends T> i = l.listIterator();

        while (low <= high) {
            int mid = (low + high) >>> 1;
            T midVal = get(i, mid);
            int cmp = c.compare(midVal, key);

            if (cmp < 0)
                low = mid + 1;
            else if (cmp > 0)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found
    }

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※網頁設計最專業,超強功能平台可客製化

※回頭車貨運收費標準

好站推薦

  • 健康醫療 減重知識專區
  • 婚紗世界 婚紗攝影寫真網
  • 成人話題 未滿18請勿進入
  • 流行時尚 時下流行愛美情報
  • 理財資訊 當舖借貸信用卡各式理財方法
  • 生活情報 各行各業情報資訊
  • 科技資訊 工業電子3C產品
  • 網路資訊 新奇趣味爆笑內容
  • 美食分享 全台各式名產 伴手禮
  • 裝潢設計 買屋賣屋裝修一羅框
  • 視覺設計 T恤、團體服、制服、polo衫

近期文章

  • 疑似小米手環 6 規格與新功能現身!加入血氧飽和偵測、GPS、更多運動模式_網頁設計公司
  • Microsoft 365 還是 Google Workspace?一文看懂企業生產力工具選哪套_如何寫文案
  • Sony Mobile 全新 Xperia Compact 小尺寸手機回歸?爆料大神釋出高清晰渲染圖_網頁設計公司
  • 微軟最新的廣告,直白地跟你說 Surface Pro 7 就是比 MacBook Pro 好_網頁設計
  • MagSafe 會干擾心律調節器?蘋果支援頁面有正式解答了_貨運

標籤

USB CONNECTOR  南投搬家公司費用 古典家具推薦 台中室內設計 台中室內設計師 台中搬家 台中搬家公司 台中電動車 台北網頁設計 台東伴手禮 台東名產 地板施工 大圖輸出 如何寫文案 婚禮錄影 宜蘭民宿 家具工廠推薦 家具訂製工廠推薦 家具訂製推薦 實木地板 床墊 復刻家具推薦 新竹婚宴會館 木地板 木質地板 柚木地板 桃園機場接送 桃園自助婚紗 沙發修理 沙發換皮 海島型木地板 潭子電動車 牛軋糖 租車 網站設計 網頁設計 網頁設計公司 貨運 超耐磨木地板 銷售文案 隱形鐵窗 電動車 馬賽克拼貼 馬賽克磁磚 馬賽克磚

彙整

  • 2021 年 4 月
  • 2021 年 3 月
  • 2021 年 2 月
  • 2021 年 1 月
  • 2020 年 12 月
  • 2020 年 11 月
  • 2020 年 10 月
  • 2020 年 9 月
  • 2020 年 8 月
  • 2020 年 7 月
  • 2020 年 6 月
  • 2020 年 5 月
  • 2020 年 4 月
  • 2020 年 3 月
  • 2020 年 2 月
  • 2020 年 1 月
  • 2019 年 12 月
  • 2019 年 11 月
  • 2019 年 10 月
  • 2019 年 9 月
  • 2019 年 8 月
  • 2019 年 7 月
  • 2019 年 6 月
  • 2019 年 5 月
  • 2019 年 4 月
  • 2019 年 3 月
  • 2019 年 2 月
  • 2019 年 1 月
  • 2018 年 12 月
©2021 值得您信賴的旅遊品牌 | 團體旅遊、自由行的專家‎ | Built using WordPress and Responsive Blogily theme by Superb