Collections.sort创建重复项吗?

时间:2019-02-22 14:38:17

标签: java sorting collections

已解决:问题最终不在于排序,而在于我不断添加经销商卡但从未删除的循环中。这最终导致向经销商分发同一张卡片两次(或多次),从而导致明显的分类问题。

所以我有要排序的此类:

public class Card implements Comparable<Card> {
    private int suit;
    private int numeral;
    private int ID;

    public Card(int cardNo) {
        assert cardNo >= 0;
        assert cardNo < 52;
        this.suit = cardNo % 4;
        this.numeral = cardNo / 4;
        this.ID = cardNo;
    }

    public int compareTo(Card otherCard) {
        return Integer.compare(this.ID, otherCard.ID);
    }

public int getSuit() {
    return this.suit;
}

public int getNumeral() {
    return this.numeral;
}

    public String toString() {
        String[] suits = {"C", "D", "H", "S"};
        //String[] suits = {"♣", "♦", "♥", "♠"}; //clubs, diamonds, hearts, spades
        String[] numerals = {"2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A"};
        return numerals[this.getNumeral()] + suits[this.getSuit()];
    }
}

当我稍后创建列表并对其进行排序时,排序似乎已中断。这是一个示例:2H 2S 3C 3D 3H 3S 4C分为2H 2S 3C 3D 3H 3S 3S。

如您所见,它创建了3S的副本并完全摆脱了4C。我在做什么错了?

编辑:这是它中断的部分:

List<Card> sortedHand = new ArrayList<>(sevenCardHand);
System.out.println(sortedHand.get(0).toString() + " " + sortedHand.get(1).toString() + " " +
        sortedHand.get(2).toString() + " " + sortedHand.get(3).toString() + " " + sortedHand.get(4).toString() +
        " " + sortedHand.get(5).toString() + " " + sortedHand.get(6).toString() + "potato");
Collections.sort(sortedHand);
System.out.println(sortedHand.get(0).toString() + " " + sortedHand.get(1).toString() + " " +
        sortedHand.get(2).toString() + " " + sortedHand.get(3).toString() + " " + sortedHand.get(4).toString() +
        " " + sortedHand.get(5).toString() + " " + sortedHand.get(6).toString() + "tomato");

没有遗漏的代码,因此不应该执行任何其他操作(因为这是一个线程),但是第二个打印输出具有重复的卡,而第一个打印输出则没有。更奇怪的是,我无法在单元测试中复制它。

EDIT2:这是完整的代码,该代码如前所述中断(使用上面的Card类)

@Test
void run() {
    SevenCardEvaluator sce = new SevenCardEvaluator();
    List<Card> deck = createDeck();
    Card playerCard2 = new Card(1);
    Card playerCard1 = new Card(0);
    deck.remove(playerCard2.getNumeral());
    deck.remove(playerCard1.getNumeral());
    for (int a = 0; a < 46; a++) {
        for (int b = a + 1; b < 47; b++) {
            for (int c = b + 1; c < 48; c++) {
                for (int d = c + 1; d < 49; d++) {
                    for (int e = d + 1; e < 50; e++) {
                        List<Card> playerHand = new ArrayList<>();
                        playerHand.add(playerCard1);
                        playerHand.add(playerCard2);
                        playerHand.add(deck.get(a));
                        playerHand.add(deck.get(b));
                        playerHand.add(deck.get(c));
                        playerHand.add(deck.get(d));
                        playerHand.add(deck.get(e));
                        int playerHandValue = sce.evaluate(playerHand);
                        List<Card> dealerDeck = new ArrayList<>(deck);
                        dealerDeck.remove(e);
                        dealerDeck.remove(d);
                        dealerDeck.remove(c);
                        dealerDeck.remove(b);
                        dealerDeck.remove(a);
                        List<Card> dealerHand = new ArrayList<>();
                        dealerHand.add(deck.get(a));
                        dealerHand.add(deck.get(b));
                        dealerHand.add(deck.get(c));
                        dealerHand.add(deck.get(d));
                        dealerHand.add(deck.get(e));
                        for (int i = 0; i < 44; i++) {
                            for (int j = i + 1; j < 45; j++) {
                                dealerHand.add(dealerDeck.get(i));
                                dealerHand.add(dealerDeck.get(j));
                                int dealerHandValue = sce.evaluate(dealerHand);
                                int playerWin = evaluateWin(playerHandValue, dealerHandValue);
                                addResult(playerWin, new int[]{deck.get(a).getNumeral(), deck.get(b).getNumeral(), deck.get(c).getNumeral(),
                                        deck.get(d).getNumeral(), deck.get(e).getNumeral()});
                            }
                        }
                    }
                }
            }
        }
    }
}

List<Card> createDeck(){
    List<Card> deck = new ArrayList<>();
    for(int i = 0; i<52; i++){
        deck.add(new Card(i));
    }
    return deck;
}

int evaluateWin(int playerHandValue, int dealerHandValue){
    return 0; //dummy method
}

void addResult(int win, int[] cardIndices){
    //dummy method
}

这是它使用的SevenCardEvaluator类:

public class SevenCardEvaluator {
    public SevenCardEvaluator(){}
    public int evaluate(List<Card> sevenCardHand){
        List<Card> sortedHand = new ArrayList<>(sevenCardHand);
        System.out.println(sortedHand.get(0).toString() + " " + sortedHand.get(1).toString() + " " +
                sortedHand.get(2).toString() + " " + sortedHand.get(3).toString() + " " + sortedHand.get(4).toString() +
                " " + sortedHand.get(5).toString() + " " + sortedHand.get(6).toString() + "potato");
        Collections.sort(sortedHand);
        System.out.println(sortedHand.get(0).toString() + " " + sortedHand.get(1).toString() + " " +
                sortedHand.get(2).toString() + " " + sortedHand.get(3).toString() + " " + sortedHand.get(4).toString() +
                " " + sortedHand.get(5).toString() + " " + sortedHand.get(6).toString() + "tomato");
//dummy class
        return -1;
    }
}

1 个答案:

答案 0 :(得分:1)

很长的帖子很抱歉,但是设计良好的对象模型可以走很长一段路。如果您将卡组和手容器化,则可以在分发卡并将其插入时互换使用。

以下是您可以在下面找到的类:

  • AbstractDeck.java
  • Actions.java
  • Card.java
  • CardHolder.java
  • Casino.java
  • Container.java
  • Deck.java
  • Hand.java
  • Player.java
  • TexasHoldem.java

赌场

一个驱动程序,用于洗牌,向玩家分发卡并对其牌进行排序。

package casino;

import java.util.*;
import java.util.stream.Collectors;

public class Casino {
    public static void main(String[] args) {
        List<Player> players = Arrays.asList("Bob", "Jill", "Thomas").stream()
                .map(Player::new).collect(Collectors.toList());
        TexasHoldem holdem = new TexasHoldem();

        holdem.dealCards(players, 2);
        holdem.sortHands(players);
        holdem.play(players);
        holdem.printInfo(players);
    }
}

输出

# FLOP
Player [name=Bob, hand=Hand [cards=[5S, JS]]] => Hand [cards=[5S, 7D, JD, JS, QD]]
Player [name=Jill, hand=Hand [cards=[9H, AH]]] => Hand [cards=[7D, 9H, JD, QD, AH]]
Player [name=Thomas, hand=Hand [cards=[4C, 8S]]] => Hand [cards=[4C, 7D, 8S, JD, QD]]

# TURN
Player [name=Bob, hand=Hand [cards=[5S, JS]]] => Hand [cards=[5H, 5S, 7D, JD, JS, QD]]
Player [name=Jill, hand=Hand [cards=[9H, AH]]] => Hand [cards=[5H, 7D, 9H, JD, QD, AH]]
Player [name=Thomas, hand=Hand [cards=[4C, 8S]]] => Hand [cards=[4C, 5H, 7D, 8S, JD, QD]]

# RIVER
Player [name=Bob, hand=Hand [cards=[5S, JS]]] => Hand [cards=[5H, 5S, 6C, 7D, JD, JS, QD]]
Player [name=Jill, hand=Hand [cards=[9H, AH]]] => Hand [cards=[5H, 6C, 7D, 9H, JD, QD, AH]]
Player [name=Thomas, hand=Hand [cards=[4C, 8S]]] => Hand [cards=[4C, 5H, 6C, 7D, 8S, JD, QD]]

# INFO
Deck [cards=[8C, TS, 3C, AD, QH, 7C, QC, 8D, TH, 4H, 4S, 6H, 2S, 6S, KC, TC, 3H, 4D, KS, 8H, JC, 9D, KH, 5D, TD, 2C, QS, KD, AC, 7S, 7H, 3S, JH, 2D, 2H, 3D, 5C, AS, 9C, 6D, 9S]]
Hand [cards=[7D, JD, QD, 5H, 6C]]
Player [name=Bob, hand=Hand [cards=[5S, JS]]]
Player [name=Jill, hand=Hand [cards=[9H, AH]]]
Player [name=Thomas, hand=Hand [cards=[4C, 8S]]]

TexasHoldem

package casino;

import java.util.List;

public class TexasHoldem {
    private Deck deck;
    private Hand communityHand;

    public TexasHoldem() {
        deck = new Deck();
        communityHand = new Hand();
        deck.shuffle();
    }

    void printInfo(List<Player> players) {
        System.out.println("# INFO");
        System.out.println(deck);
        System.out.println(communityHand);
        players.stream().forEach(System.out::println);
    }

    void play(List<Player> players) {
        for (int i = 0; i < 5; i++) {
            communityHand.insert(deck.draw());
            if (i == 2) {
                System.out.println("# FLOP");
                compareHands(players, communityHand);
                System.out.println();
            }
            if (i == 3) {
                System.out.println("# TURN");
                compareHands(players, communityHand);
                System.out.println();
            }
            if (i == 4) {
                System.out.println("# RIVER");
                compareHands(players, communityHand);
                System.out.println();
            }
        }
    }

    public Hand viewHand(Player player, Hand community) {
        Hand view = new Hand();
        for (Card card : player.getHand().getCards()) {
            view.insert(card);
        }
        for (Card card : community.getCards()) {
            view.insert(card);
        }
        return view;
    }

    public void compareHands(List<Player> players, Hand community) {
        for (Player player : players) {
            Hand view = viewHand(player, community);
            view.sort();
            System.out.printf("%s => %s%n", player, view);
        }
    }

    public void dealCards(List<Player> players, int cardsPerPlayer) {
        for (int round = 0; round < cardsPerPlayer; round++) {
            for (Player player : players) {
                player.getHand().insert(deck.draw());
            }
        }
    }

    void sortHands(List<Player> players) {
        for (Player player : players) {
            player.getHand().sort();
        }
    }
}

甲板

按级别和西装划分的52张标准扑克牌。

package casino;

import java.util.*;

public class Deck extends AbstractDeck<Card> implements CardHolder {
    public Deck() {
        items = new Stack<Card>();
        for (int cardNo = 0; cardNo < 52; cardNo++) {
            items.add(new Card(cardNo));
        }
    }

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

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

    @Override
    public String toString() {
        return String.format("Deck [cards=%s]", items);
    }
}

播放器

持有一手牌的玩家。

package casino;

public class Player {
    private String name;
    private Hand hand;

    public String getName() {
        return name;
    }

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

    public Hand getHand() {
        return hand;
    }

    public void setHand(Hand hand) {
        this.hand = hand;
    }

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

    public Player(String name) {
        this(name, new Hand());
    }

    @Override
    public String toString() {
        return String.format("Player [name=%s, hand=%s]", name, hand);
    }
}

代表一手牌。

package casino;

import java.util.*;

public class Hand extends AbstractDeck<Card> implements CardHolder {
    public Hand() {
        items = new Stack<Card>();
    }

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

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

    @Override
    public String toString() {
        return String.format("Hand [cards=%s]", items);
    }
}

代表具有花色和等级的标准扑克牌。

package casino;

public class Card implements Comparable<Card> {
    public static final String[] SUIT = { "C", "D", "H", "S" };
    public static final String[] RANK = { "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K", "A" };

    private int id;
    private int suit;
    private int numeral;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getSuit() {
        return suit;
    }

    public void setSuit(int suit) {
        this.suit = suit;
    }

    public int getNumeral() {
        return numeral;
    }

    public void setNumeral(int numeral) {
        this.numeral = numeral;
    }

    public Card(int cardNo) {
        assert cardNo >= 0;
        assert cardNo < 52;

        this.id = cardNo;
        this.suit = cardNo % 4;
        this.numeral = cardNo / 4;
    }

    public int compareTo(Card otherCard) {
        return Integer.compare(this.id, otherCard.id);
    }

    public String toString() {
        return String.format("%s%s", RANK[this.getNumeral()], SUIT[this.getSuit()]);
    }
}

CardHolder

由于它们扩展了AbstractDeck,因此被用来将卡片组和手牌当作卡片持有人。

package casino;

public interface CardHolder extends Container<Card> {
    // Just used as a category for Collection utilities of need be.
}

容器

一个模拟通用项目堆栈的界面,例如卡。

package casino;

public interface Container<E> {
    E peek();
    E draw();
    boolean insert(E element);
    void insertAt(int index, E element);
    void shuffle();
    void sort();
}

AbstractDeck

包含可比较项的Container的抽象实现。从这个意义上说,甲板和手非常相似。

package casino;

import java.util.Stack;

public class AbstractDeck<T extends Comparable<T>> implements Container<T> {
    protected Stack<T> items;

    @Override
    public T peek() {
        return items.peek();
    }

    @Override
    public T draw() {
        return items.pop();
    }

    @Override
    public boolean insert(T item) {
        return items.add(item);
    }

    @Override
    public void insertAt(int index, T item) {
        items.add(index, item);
    }

    @Override
    public void shuffle() {
        Actions.shuffle(items);
    }

    @Override
    public void sort() {
        Actions.sort(items);
    }
}

动作

用于对通用列表进行操作的静态实用程序类。

package casino;

import java.util.*;

public class Actions {
    private static final Random rnd = new Random();

    /** Fisher–Yates shuffle */
    public static <E> void shuffle(List<E> list) {
        for (int i = list.size() - 1; i > 0; i--) {
            int index = rnd.nextInt(i + 1);
            E tmp = list.get(index);
            list.set(index, list.get(i));
            list.set(i, tmp);
        }
    }

    public static <E extends Comparable<E>> void sort(List<E> list) {
        Collections.sort(list);
    }
}