开发者

Sorting a deck of cards by suit and then rank

I have this Java class:

class Card
{
    privat开发者_JS百科e Suit suit;
    private int  rank;
}

(Suit is an enum)

There are four suits with ranks 1-9 each and four suits with a single possible rank 0. Each card exists in an unknown but constant among all cards number of copies. How would I sort a deck in a set order of suits, and by increasing rank in each suit?


You'll need to either

  1. implement the Comparable interface on the card object: add a compareTo function that determines whether another card should be before or after this one in the sort order
  2. implement a Comparator object that accepts two cards and indicates which order they should appear in

and then you can use Collections.sort on your list.


Have a look at implementing Comparable on the enum.


Make Rank an enum too and you can deal a sorted deck as such:

    for (Suit suit : Suit.values())
        for (Rank rank : Rank.values())
            deck.add(new Card(rank, suit));


make it implement the Comparable interface. Theres only only one method you'll need to write. Then they can be compared to each other, and you have a number of existing sort options, such as static Arrays.sort if you have an array or Collections.sort if its any kind of Collection (List, Vector, etc)

Besides implementing on Card you might have to do the same for Suit depending on how its done.


Here would be an example of the Card Class. As the questions states the Suit would be of a specific class while the Rank would be an integer (in this example I didn't implement rank validation). Implementing the Comparable class allows a Card class to compare another Card Class. So that a List/Set of Cards can be sorted.

public class Card implements Comparable<Card>{

    private SUIT cardSuit;
    private int cardRank;

    public enum SUIT {SPADE, CLUB, HEART, DIAMOND};

    public Card(int cardRank, SUIT cardSuit) {
        this.cardSuit = cardSuit;
        this.cardRank = cardRank;
    }

    /**
     * Generates a random card
     */
    public Card(){
        this((int) (Math.random() * 9) , SUIT.values()[(int) (Math.random() * SUIT.values().length)]);
    }

    public String getSuit() {
        return cardSuit.toString();
    }

    public int getRank() {
        return cardRank;
    }

    @Override
    public int compareTo(Card2 o) {
        if (this.cardRank == o.cardRank) {
            return this.cardSuit.compareTo(o.cardSuit);
        } else {
            return o.cardRank - this.cardRank;
        }
    }

}


A fast way to accomplish this task is by Radix Sort. Set up an array of lists of card values, then walk through your deck, placing each card into the appropriate list as you encounter it. Then merge all the lists together into a partially sorted deck. Now do the same thing, only with an array of lists of suits. Merge all the lists together and you should have a sorted deck.


Although I don't see it posted now, I believe that the original poster was working with a representation of cards that is very similar to the one that I worked with. Specifically, I remember seeing cards in the original post similar to the following format: [ 'As', 'Kd', '4c', '6h' . . ..], i.e., Ace of Spades, King of Diamonds, 4 of Clubs, and 6 of Hearts, etc. In my case, I was working with a whole deck of cards represented as follows: [AcQhJd8h9c9h6d3cTc3dQdKhJs6h3hThQc7d3sJc4h2h6c8d7c5c7s8cAd4dTd9sKs5h8s2c4c2d2s5sAhKd9dKcQs4s5dAs7hJhTs6s] This deck is one of hundreds of thousands of decks found by Mathematician Jeremy Kun where a two player game of Texas Holdem always results in a win for Player #1 no matter where the deck is cut (but not shuffled). For more details, see, https://jeremykun.com/2012/04/09/optimal-stacking-hold-em/ I found that reading each card as text and trying to figure who won and who lost with what hole cards, burn cards, and community cards (flop, turn and river) was well nigh impossible. I wanted to see actual cards separated for each player's hole cards, the community cards, etc. The format of the deck of cards is understandable, but it is not in the form of an actual array that would be recognized using JavaScript. So, I started by turning it into a string by replacing the square brackets with quote marks. From there, I could use string methods to take two characters at a time and translate them into visible cards. I could have done that any number of ways, but I chose to use Unicode card characters since they behave just like text and can be resized and be given different colors with CSS, just like text. The format for displaying a Unicode card character within the inner html of an element, e.g., a span element, is to use the code pattern &#x1f0_ _ ; where the two blanks will be first a hex number for the suit and then a hex number for the rank of the card. The possible hex numbers for the suits are 'a' = spades, 'b' = hearts, 'c' = diamonds, and 'd' = clubs. The possible hex numbers for the rank of each card are: '1' = ace, '2' = 2, . . . 'a' = 10, 'b' = Jack, 'c' = "Count" (not used in poker, as in Count Dracula never gets invited to poker games), 'd' = Queen, and 'e' = King. When using the code pattern &#x1f0_ _; the length of the characters will be 9 characters when first coded, but after the card is displayed on an html page, the browser converts the code into two characters, which will change the length of your html element for each card. For example, a span element with no attributes and inner html code for a card would be 22 characters long, but after being displayed on an html page, the length would change to 7 less (i.e., 15). My code for displaying the above deck as Unicode card characters is fairly short:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display Deck</title>
<style type="text/css">
body {
    font-size: 21pt;
}
span {
    background-color: white;
}
.aspade {
        color: black;
}
.bheart {
        color: red;
}
.cdiams {
        color: mediumvioletred;
}
.dclubs {
        color: blue; 
}
</style>
</head>
<body>
<p id="displayPoint"></p>
<script type="text/javascript">
 let holdemWinDeck = 'AcQhJd8h9c9h6d3cTc3dQdKhJs6h3hThQc7d3sJc4h2h6c8d7c5c7s8cAd4dTd9sKs5h8s2c4c2d2s5sAhKd9dKcQs4s5dAs7hJhTs6s'; 
let displayDeck = [];
let rankTranslate = {'A':'1', '2':'2', '3':'3', '4':'4', '5':'5', '6':'6', '7':'7', '8':'8', '9':'9', 'T':'a', 'J':'b', 'Q':'d', 'K':'e'};
let suitTranslate = {'h':'b', 'c':'d', 'd':'c', 's':'a'};
    for (let i = 0; i < holdemWinDeck.length; i += 2) { 
                let unicodeCardRank = rankTranslate[holdemWinDeck.slice(i, i + 1)];         
                let unicodeCardSuit = suitTranslate[holdemWinDeck.slice(i + 1, i + 2)];                 
                let plainSuitNameTranslate = {'b':'bheart', 'd':'dclubs', 'c':'cdiams', 'a':'aspade'};
                let className = plainSuitNameTranslate[unicodeCardSuit];
                let card = (`<span onclick='cutCards(this.outerHTML);' class='${className}'>&#x1f0${unicodeCardSuit}${unicodeCardRank};</span>`);
                displayDeck.push(card);             
                }
document.getElementById('displayPoint').innerHTML=displayDeck.join('');
</script>
</body> 
</html>

When I first tried to use the string method, .slice(), to access the suit and rank number for each card, I hit a wall. The two characters are actually four characters each, which are known as the "surrogate pair" of Unicode codes that are used under the hood of the browser to display a card since the longer code first written has to be translated by the browser into two shorter codes to represent and display the card. Worse, when you query for the length of either surrogate pair of four characters, you will get back a length of one. You will not be allowed to use slice() among the four characters of either surrogate pair. The first surrogate (called the "high surrogate") is always the same four characters for any Unicode card character, and the second surrogate (called the "low surrogate" has the same first two characters for any Unicode card character, but the last two characters are where the magic happens, they are the very same two characters for suit and rank as in the original code. I knew that I would need to access those two codes so that I could ask questions about suit or rank in any given sequence of cards. For example, to determine whether a player's two hole cards and five community cards hold a Royal Flush, I would need to ask if there were five cards of the same suit and whether those cards were in a numerical sequence of one number apart with an ace at the top. (Ultimately, I did it differently, and plan to change it yet again, but I still need access to suit and rank information among the cards.) I searched the Internet and found my solution in two methods that I had never really used or understood before:

for (let i = 0; i < arr7.length; i++) { suit[i] = arr7[i].slice(57, 59).codePointAt(0).toString(16).slice(3, 4); rank[i] = lowAcesAnd_C_Gap[arr7[i].slice(57, 59).codePointAt(0).toString(16).slice(4, 5)]; } The variable arr7 is an array of a player's two hole cards concatenated with the community cards and then sorted (.sort() ), which puts the cards into suit order first and then into rank order within each suit. So, my new arrays of suit and rank will follow the same order as the original sorted arr7. I may then ask suit and rank questions in my JavaScript code, and, if satisfied, pull actual cards from the same positions in the original arr7. I have found that I need to sort purely by rank but still have access to the card, so I have also created an array that puts the rank before the actual card so that I will still have access to the card after I sort purely by rank.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜