Collections.sort создает дубликаты? - PullRequest
0 голосов
/ 22 февраля 2019

решено: В конечном итоге проблема заключалась не в сортировке, а в моих циклах, где я продолжал добавлять карты дилеров, но никогда не удалял их.Это привело к тому, что в конце концов дилер дважды (или больше) кормил одну и ту же карту, что приводило к очевидной проблеме сортировки.

Итак, у меня есть этот класс, который я хочу отсортировать:

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 голосов
/ 22 февраля 2019

Извините за длинный пост, но хорошо разработанная объектная модель может иметь большое значение.Если вы упаковываете колоду и руки, то вы можете использовать их взаимозаменяемо при раздаче карт и их вставке.

Вот классы, которые вы можете найти ниже:

  • 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);
    }
}

Ouput

# 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

Абстрактная реализация Контейнера, содержащего сопоставимые элементы,Колода и рука очень похожи в этом смысле.

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...