我已经有12年的程序员工作经验,主要是ERP软件和C开发,并且
希望能够改变Java的职业/专业。我已经阅读了无数次
,如果您想学习一种新语言,则需要编写代码,然后再编写更多的代码,最后编写更多的代码。所以我写了一些代码!

我喜欢扑克,所以我写了一个小的Texas Hold'em程序。以下是其功能概述:


向用户询问玩家人数
创建牌组
随机播放
切牌
玩家处理卡洞
烧卡
转牌
烧卡
转身
烧卡
河卡
>将纸牌打印到控制台以显示使用了随机纸牌
打印“棋盘”
打印烧录卡
打印机玩家卡
评估每个玩家的手牌值(皇家同花顺,满屋等等。)

有6个.java文件(请参阅下面的链接)。我使用了一个接口,创建了自己的比较器,甚至实现了一些try / catch块(尽管我仍在学习如何正确使用它们)。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class TexasHoldEm {

    public static void main(String[] args) throws Exception {
        // variables
        Deck holdemDeck = new Deck();
        int numPlayers = 0;
        int cardCounter = 0;
        int burnCounter = 0;
        int boardCounter = 0;
        Board board = new Board();

        // initializations      
        numPlayers = getNumberOfPlayers();
        Player[] player = new Player[numPlayers];

        /* 3 shuffles just like in real life. */
        for(int i=0;i<3;i++){
            holdemDeck.shuffle();
        }

        // Cut Deck
        holdemDeck.cutDeck();

        // Initialize players
        for (int i=0;i<numPlayers;i++){
            player[i] = new Player();
        }

        // Main processing
        // Deal hole cards to players
        for (int i=0;i<2;i++){
            for (int j=0;j<numPlayers;j++){
                player[j].setCard(holdemDeck.getCard(cardCounter++), i);
            }
        }

        // Start dealing board

        // Burn one card before flop
        board.setBurnCard(holdemDeck.getCard(cardCounter++), burnCounter++);

        // deal flop
        for (int i=0; i<3;i++){
            board.setBoardCard(holdemDeck.getCard(cardCounter++), boardCounter++);
        }

        // Burn one card before turn
        board.setBurnCard(holdemDeck.getCard(cardCounter++), burnCounter++);

        // deal turn
        board.setBoardCard(holdemDeck.getCard(cardCounter++), boardCounter++);

        // Burn one card before river
        board.setBurnCard(holdemDeck.getCard(cardCounter++), burnCounter++);

        // deal river
        board.setBoardCard(holdemDeck.getCard(cardCounter++), boardCounter++);

        //------------------------
        // end dealing board
        //------------------------

        System.out.println("The hand is complete...\n");

        // print deck
        holdemDeck.printDeck();

        //print board
        board.printBoard();

        // print player cards
        System.out.println("The player cards are the following:\n");
        for (int i=0;i<numPlayers;i++){
            player[i].printPlayerCards(i);
        }

        // print burn cards
        board.printBurnCards();

        //------------------------
        // Begin hand comparison
        //------------------------
        for (int i=0;i<numPlayers;i++){
            HandEval handToEval = new HandEval();

            // populate with player cards           
            for (int j=0;j<player[i].holeCardsSize();j++){
                handToEval.addCard(player[i].getCard(j),j);
            }

            //populate with board cards
            for (int j=player[i].holeCardsSize();j<(player[i].holeCardsSize()+board.boardSize());j++){
                handToEval.addCard(board.getBoardCard(j-player[i].holeCardsSize()),j);
            }

            System.out.println("Player " + (i+1) + " hand value: " + handToEval.evaluateHand());    
        }
    }

    protected static int getNumberOfPlayers() throws Exception{
        int intPlayers = 0;
        String userInput = "";

        // Get number of players from user.
        System.out.println("Enter number of players (1-9):");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        try { 
               userInput = br.readLine(); 
            } catch (IOException ioe) { 
               System.out.println("Error: IO error trying to read input!"); 
               System.exit(1); 
            }

        // convert user input to an integer
        try {
           intPlayers = Integer.parseInt(userInput);
            } catch (NumberFormatException nfe) {
               System.out.println("Error: Input provided is not a valid Integer!"); 
               System.exit(1); 
            }

        if ((intPlayers<1) || (intPlayers>9)){
            throw new Exception("Error: Number of players must be an integer between 1 and 9");
        }       

        return intPlayers;
    }
}


播放器。 java

public class Player {
    private Card[] holeCards = new Card[2];

    //constructor
    public Player(){
    }

    public Player(Card card1, Card card2){
        holeCards[0] = card1;
        holeCards[1] = card2;
    }

    //methods
    protected void setCard(Card card, int cardNum){
        holeCards[cardNum] = card;
    }

    protected Card getCard(int cardNum){
        return holeCards[cardNum];
    }

    protected int holeCardsSize(){
        return holeCards.length;
    }

    protected void printPlayerCards(int playerNumber){
        System.out.println("Player " + (playerNumber+1) + " hole cards:");
        for (int i=0;i<2;i++){
            System.out.println(holeCards[i].printCard());
        }
        System.out.println("\n");
    }
}


HandEval.java

import java.util.Arrays;

public class HandEval { 
    private Card[] availableCards = new Card[7];

    private final static short ONE = 1;
    private final static short TWO = 2;
    private final static short THREE = 3;
    private final static short FOUR = 4;

    // Constructor
    public HandEval(){
    }

    //methods
    protected void addCard(Card card, int i){
        availableCards[i] = card;
    }

    protected Card getCard(int i){
        return availableCards[i];
    }

    protected int numCards(){
        return availableCards.length;
    }

    protected void sortByRank(){
        Arrays.sort(availableCards, new rankComparator());
    }

    protected void sortBySuit(){
        Arrays.sort(availableCards, new suitComparator());
    }

    protected void sortBySuitThenRank(){
        Arrays.sort(availableCards, new suitComparator());
        Arrays.sort(availableCards, new rankComparator());
    }

    protected void sortByRankThenSuit(){
        Arrays.sort(availableCards, new rankComparator());
        Arrays.sort(availableCards, new suitComparator());
    }

    protected String evaluateHand(){
        String handResult = new String();
        short[] rankCounter = new short[13];
        short[] suitCounter = new short[4];

        // initializations
        for (int i=0;i<rankCounter.length;i++){
            rankCounter[i] =0;
        }

        for (int i=4;i<suitCounter.length;i++){
            suitCounter[i] = 0;
        }

        // Loop through sorted cards and total ranks
        for(int i=0; i<availableCards.length;i++){
            rankCounter[ availableCards[i].getRank() ]++;
            suitCounter[ availableCards[i].getSuit() ]++;
        }

        //sort cards for evaluation
        this.sortByRankThenSuit();

        // hands are already sorted by rank and suit for royal and straight flush checks.       
        // check for royal flush
        handResult = evaluateRoyal(rankCounter, suitCounter);

        // check for straight flush
        if (handResult == null || handResult.length() == 0){
            handResult = evaluateStraightFlush(rankCounter, suitCounter);
        }

        // check for four of a kind
        if (handResult == null || handResult.length() == 0){
            handResult = evaluateFourOfAKind(rankCounter);
        }

        // check for full house
        if (handResult == null || handResult.length() == 0){
            handResult = evaluateFullHouse(rankCounter);
        }

        // check for flush
        if (handResult == null || handResult.length() == 0){
            handResult = evaluateFlush(rankCounter, suitCounter);
        }

        // check for straight
        if (handResult == null || handResult.length() == 0){
            // re-sort by rank, up to this point we had sorted by rank and suit
            // but a straight is suit independent.
            this.sortByRank();
            handResult = evaluateStraight(rankCounter);
        }

        // check for three of a kind
        if (handResult == null || handResult.length() == 0){
            handResult = evaluateThreeOfAKind(rankCounter);
        }

        // check for two pair
        if (handResult == null || handResult.length() == 0){
            handResult = evaluateTwoPair(rankCounter);
        }

        // check for one pair
        if (handResult == null || handResult.length() == 0){
            handResult = evaluateOnePair(rankCounter);
        }

        // check for highCard
        if (handResult == null || handResult.length() == 0){
            handResult = evaluateHighCard(rankCounter);
        }


        return handResult;
    }

    private String evaluateRoyal(short[] rankCounter, short[] suitCounter){
        String result = "";

        // Check for Royal Flush (10 - Ace of the same suit).
        // check if there are 5 of one suit, if not royal is impossible     
        if ((rankCounter[9] >= 1 &&       /* 10 */
                rankCounter[10] >= 1 &&   /* Jack */
                rankCounter[11] >= 1 &&  /* Queen */
                rankCounter[12] >= 1 &&  /* King */
                rankCounter[0] >= 1)    /* Ace */
                && (suitCounter[0] > 4 || suitCounter[1] > 4 ||
                        suitCounter[2] > 4 || suitCounter[3] > 4)){

            // min. requirements for a royal flush have been met, 
            // now loop through records for an ace and check subsequent cards. 
            // Loop through the aces first since they are the first card to 
            // appear in the sorted array of 7 cards. 
            royalSearch:
                for (int i=0;i<3;i++){
                    // Check if first card is the ace.
                    // Ace must be in position 0, 1 or 2
                    if (availableCards[i].getRank() == 0){
                        // because the ace could be the first card in the array
                        // but the remaining 4 cards could start at position 1,
                        // 2 or 3 loop through checking each possibility.
                        for (int j=1;j<4-i;j++){
                            if ((availableCards[i+j].getRank() == 9 && 
                                    availableCards[i+j+1].getRank() == 10 &&
                                    availableCards[i+j+2].getRank() == 11 &&
                                    availableCards[i+j+3].getRank() == 12) 
                                    &&
                                    (availableCards[i].getSuit() == availableCards[i+j].getSuit() &&
                                    availableCards[i].getSuit() == availableCards[i+j+1].getSuit() &&
                                    availableCards[i].getSuit() == availableCards[i+j+2].getSuit() &&
                                    availableCards[i].getSuit() == availableCards[i+j+3].getSuit())){
                                        // Found royal flush, break and return.
                                        result = "Royal Flush!! Suit: " + Card.suitAsString(availableCards[i].getSuit());
                                        break royalSearch;              
                            }
                        }
                    }               
                }
        }       
        return result;
    }

    // Straight flush is 5 consecutive cards of the same suit.
    private String evaluateStraightFlush(short[] rankCounter, short[] suitCounter){
        String result = "";

        if (suitCounter[0] > 4 || suitCounter[1] > 4 ||
                suitCounter[2] > 4 || suitCounter[3] > 4){

            // min. requirements for a straight flush have been met.
            // Loop through available cards looking for 5 consecutive cards of the same suit,
            // start in reverse to get the highest value straight flush
            for (int i=availableCards.length-1;i>3;i--){
                if ((availableCards[i].getRank()-ONE == availableCards[i-ONE].getRank() && 
                        availableCards[i].getRank()-TWO == availableCards[i-TWO].getRank() &&
                        availableCards[i].getRank()-THREE == availableCards[i-THREE].getRank() &&
                        availableCards[i].getRank()-FOUR == availableCards[i-FOUR].getRank()) 
                        &&
                        (availableCards[i].getSuit() == availableCards[i-ONE].getSuit() &&
                        availableCards[i].getSuit() == availableCards[i-TWO].getSuit() &&
                        availableCards[i].getSuit() == availableCards[i-THREE].getSuit() &&
                        availableCards[i].getSuit() == availableCards[i-FOUR].getSuit())){
                            // Found royal flush, break and return.
                            result = "Straight Flush!! " + Card.rankAsString(availableCards[i].getRank()) + " high of " + Card.suitAsString(availableCards[i].getSuit());
                            break;
                }
            }
        }
        return result;
    }

    // Four of a kind is 4 cards with the same rank: 2-2-2-2, 3-3-3-3, etc...
    private String evaluateFourOfAKind(short[] rankCounter){
        String result = "";

        for (int i=0;i<rankCounter.length;i++){
            if (rankCounter[i] == FOUR){
                result = "Four of a Kind, " + Card.rankAsString(i) +"'s";
                break;
            }
        }   
        return result;
    }

    // Full house is having 3 of a kind of one rank, and two of a kind of 
    // a second rank.  EX: J-J-J-3-3
    private String evaluateFullHouse(short[] rankCounter){
        String result = "";
        short threeOfKindRank = -1;
        short twoOfKindRank = -1;

        for (int i=rankCounter.length;i>0;i--){
            if ((threeOfKindRank < (short)0) || (twoOfKindRank < (short)0)){
                if ((rankCounter[i-ONE]) > 2){
                    threeOfKindRank = (short) (i-ONE);                  
                }
                else if ((rankCounter[i-ONE]) > 1){
                    twoOfKindRank = (short)(i-ONE);
                }
            }
            else
            {
                break;
            }
        }

        if ((threeOfKindRank >= (short)0) && (twoOfKindRank >= (short)0)){
            result = "Full House: " + Card.rankAsString(threeOfKindRank) + "'s full of " + Card.rankAsString(twoOfKindRank) + "'s";
        }

        return result;
    }

    // Flush is 5 cards of the same suit.
    private String evaluateFlush(short[] rankCounter, short[] suitCounter){
        String result = "";

        // verify at least 1 suit has 5 cards or more.
        if (suitCounter[0] > 4 || suitCounter[1] > 4 ||
                suitCounter[2] > 4 || suitCounter[3] > 4){

            for (int i=availableCards.length-1;i>3;i--){
                if (availableCards[i].getSuit() == availableCards[i-ONE].getSuit() &&
                        availableCards[i].getSuit() == availableCards[i-TWO].getSuit() &&
                        availableCards[i].getSuit() == availableCards[i-THREE].getSuit() &&
                        availableCards[i].getSuit() == availableCards[i-FOUR].getSuit()){
                            // Found royal flush, break and return.
                            result = "Flush!! " + Card.rankAsString(availableCards[i].getRank()) + " high of " + Card.suitAsString(availableCards[i].getSuit());
                            break;
                }
            }           
        }


        return result;
    }

    // Straight is 5 consecutive cards, regardless of suit.
    private String evaluateStraight(short[] rankCounter){
        String result = "";

        // loop through rank array to check for 5 consecutive
        // index with a value greater than zero
        for (int i=rankCounter.length;i>4;i--){
            if ((rankCounter[i-1] > 0) &&
                    (rankCounter[i-2] > 0) &&
                    (rankCounter[i-3] > 0) &&
                    (rankCounter[i-4] > 0) &&
                    (rankCounter[i-5] > 0)){
                        result = "Straight " + Card.rankAsString(i-1) + " high";
                        break;
            }
        }
        return result;
    }

    // Three of a kind is 3 cards of the same rank.
    private String evaluateThreeOfAKind(short[] rankCounter){
        String result = "";

        // loop through rank array to check for 5 consecutive
        // index with a value greater than zero
        for (int i=rankCounter.length;i>0;i--){
            if (rankCounter[i-1] > 2){
                        result = "Three of a Kind " + Card.rankAsString(i-1) + "'s";
                        break;
            }
        }
        return result;
    }

    // Two pair is having 2 cards of the same rank, and two
    // different cards of the same rank.  EX: 3-3-7-7-A
    private String evaluateTwoPair(short[] rankCounter){
        String result = "";
        short firstPairRank = -1;
        short secondPairRank = -1;

        for (int i=rankCounter.length;i>0;i--){
            if ((firstPairRank < (short)0) || (secondPairRank < (short)0)){             
                if (((rankCounter[i-ONE]) > 1) && (firstPairRank < (short)0)){
                    firstPairRank = (short) (i-ONE);                    
                }
                else if ((rankCounter[i-ONE]) > 1){
                    secondPairRank = (short)(i-ONE);
                }
            }
            else
            {
                // two pair found, break loop.
                break;
            }
        }

        // populate output
        if ((firstPairRank >= (short)0) && (secondPairRank >= (short)0)){
            if (secondPairRank == (short)0){
                // Aces serve as top rank but are at the bottom of the rank array
                // swap places so aces show first as highest pair
                result = "Two Pair: " + Card.rankAsString(secondPairRank) + "'s and " + Card.rankAsString(firstPairRank) + "'s";
            }
            else
            {
                result = "Two Pair: " + Card.rankAsString(firstPairRank) + "'s and " + Card.rankAsString(secondPairRank) + "'s";
            }           
        }

        return result;
    }

    // One is is two cards of the same rank.
    private String evaluateOnePair(short[] rankCounter){
        String result = "";

        for (int i=rankCounter.length;i>0;i--){
            if((rankCounter[i-ONE]) > 1){
                result = "One Pair: " + Card.rankAsString(i-ONE) + "'s";    
                break;
            }
        }
        return result;
    }

    // high card is the highest card out of the 7 possible cards to be used.
    private String evaluateHighCard(short[] rankCounter){
        String result = "";

        for (int i=rankCounter.length;i>0;i--){
            if((rankCounter[i-ONE]) > 0){
                result = "High Card: " + Card.rankAsString(i-ONE);
                break;
            }
        }
        return result;
    }

}


Deck.java

import java.util.Random;

public class Deck{
    private Card[] cards = new Card[52];

    //Constructor
    public Deck(){
        int i = 0;
        for (short j=0; j<4; j++){
            for (short k=0; k<13;k++){
                cards[i++] = new Card(k, j);    
            }
        }
    }

    // Print entire deck in order
    protected void printDeck(){
        for(int i=0; i<cards.length;i++){
            System.out.println(i+1 + ": " + cards[i].printCard());
        }
        System.out.println("\n");
    }

    // Find card in deck in a linear fashion
    // Use this method if deck is shuffled/random
    protected int findCard(Card card){
        for (int i=0;i<52;i++){
            if (Card.sameCard(cards[i], card)){
                return i;
            }
        }
        return -1;
    }

    //return specified card from deck
    protected Card getCard(int cardNum){
        return cards[cardNum];
    }

    protected void shuffle(){
        int length = cards.length;
        Random random = new Random();
        //random.nextInt();
        for (int i=0;i<length;i++){
            int change = i + random.nextInt(length-i);
            swapCards(i, change);
        }
    }

    protected void cutDeck(){
        Deck tempDeck = new Deck();
        Random random = new Random();
        int cutNum = random.nextInt(52);
        for (int i=0;i<cutNum;i++){
            tempDeck.cards[i] = this.cards[52-cutNum+i];            
        }
        for (int j=0;j<52-cutNum;j++){
            tempDeck.cards[j+cutNum] = this.cards[j];           
        }
        this.cards = tempDeck.cards;
    }

    // Swap cards in array to 'shuffle' the deck.
    private void swapCards(int i, int change){      
        Card temp = cards[i];
        cards[i] = cards[change];
        cards[change] = temp;
    }
}


Card.java

import java.util.*;

public class Card{
    private short rank, suit;

    private static String[] ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
    private static String[] suits = {"Diamonds", "Clubs", "Hearts", "Spades"};

    //Constructor
    public Card(short rank, short suit){
        this.rank = rank;
        this.suit = suit;
    }

    // Getter and Setters
    public short getSuit(){
        return suit;
    }

    public short getRank(){
        return rank;
    }

    protected void setSuit(short suit){
        this.suit = suit;
    }

    protected void setRank(short rank){
        this.rank = rank;
    }

    // methods
    public static String rankAsString(int __rank){
        return ranks[__rank];
    }

    public static String suitAsString(int __suit){
        return suits[__suit];
    }

    public @Override String toString(){
        return rank + " of " + suit;
    }

    // Print card to string
    protected String printCard(){
        return ranks[rank] + " of " + suits[suit];
    }

    // Determine if two cards are the same (Ace of Diamonds == Ace of Diamonds)
    public static boolean sameCard(Card card1, Card card2){
        return (card1.rank == card2.rank && card1.suit == card2.suit);
    }   

}

class rankComparator implements Comparator<Object>{
    public int compare(Object card1, Object card2) throws ClassCastException{
        // verify two Card objects are passed in
        if (!((card1 instanceof Card) && (card2 instanceof Card))){
            throw new ClassCastException("A Card object was expeected.  Parameter 1 class: " + card1.getClass() 
                    + " Parameter 2 class: " + card2.getClass());
        }

        short rank1 = ((Card)card1).getRank();
        short rank2 = ((Card)card2).getRank();

        return rank1 - rank2;
    }
}

class suitComparator implements Comparator<Object>{
    public int compare(Object card1, Object card2) throws ClassCastException{
        // verify two Card objects are passed in
        if (!((card1 instanceof Card) && (card2 instanceof Card))){
            throw new ClassCastException("A Card object was expeected.  Parameter 1 class: " + card1.getClass() 
                    + " Parameter 2 class: " + card2.getClass());
        }

        short suit1 = ((Card)card1).getSuit();
        short suit2 = ((Card)card2).getSuit();

        return suit1 - suit2;
    }
}


Board.java

public class Board {
    private Card[] board = new Card[5];
    private Card[] burnCards = new Card[3];

    //constructor
    public Board(){
    }

    //methods
    protected void setBoardCard(Card card, int cardNum){
        this.board[cardNum] = card;
    }

    protected Card getBoardCard(int cardNum){
        return this.board[cardNum];
    }

    protected void setBurnCard(Card card, int cardNum){
        this.burnCards[cardNum] = card;
    }

    protected Card getBurnCard(int cardNum){
        return this.burnCards[cardNum];
    }

    protected int boardSize(){
        return board.length;
    }

    protected void printBoard(){
        System.out.println("The board contains the following cards:");
        for(int i =0; i<board.length;i++){
            System.out.println(i+1 + ": " + getBoardCard(i).printCard());
        }
        System.out.println("\n");
    }

    protected void printBurnCards(){
        System.out.println("The burn cards are:");
        for(int i =0; i<burnCards.length;i++){
            System.out.println(i+1 + ": " + getBurnCard(i).printCard());
        }
        System.out.println("\n");
    }

}


评论

请根据常见问题解答,在帖子中包含要查看的代码的主要部分。谢谢

@Mark Loeser:好的,我真的希望整个程序都在研究,发布会非常冗长,所以我认为将代码发布到pastebin会更好。我将修改我的帖子。

顺便说一句,我不想​​劝阻您学习Java,但是如果您的Hold'em示例是您计划进行的编程的典型示例,那么您可能会对功能语言感兴趣。以Scala为例,它基本上是具有功能特性的Java。

@RoToRa:我想学习Java,我只是想不出要编写学习它的程序。从Internet上进行教程很快就会变得陈旧,并且不允许我以自己感兴趣的水平解决问题。我过去的经验是在C中工作,所以这可能就是为什么我以这种方式编写程序的原因。我还希望有一些代码示例,因此在面试时,我会向他们展示一些东西,因为我还没有任何使用该语言的经验。

众所周知,扑克很难与OOP一起使用。大酒杯的效果更好。此外,本教程站点还提供了许多有关扑克方面的Java练习,这些练习是更复杂练习的基础。您还将学习GUI,IO,线程,ADT和泛型,它们比IMHO的级别更高。我认为这是相当不错的东西:)

#1 楼

让我们从最基本的Card类开始。而不是使用通配符。


import java.util.*;



将等级和西服存储为short无疑是一个有效的选择,因为它很可能最快,最有效的方法,但是如果您想学习Java的特定知识,则可能需要研究枚举。


public class Card{
    private short rank, suit;



IMHO卡是不可变对象的主要示例。没有理由需要更改牌的等级或花色,所以我会丢掉二传手。


protected void setSuit(short suit){
    this.suit = suit;
}

protected void setRank(short rank){
    this.rank = rank;
}



在Java变量名中使用下划线非常不寻常,尤其是两个前缀。我会简单地命名参数ranksuit,尤其是因为它们是类(静态)方法而不是实例方法,因此与字段没有混淆。

如果这些实际上必须是类方法,而不应该是实例方法。如果您还有其他需要独立于short类将Card转换为相应名称的类,则可以。但就您的情况而言,我会说并非如此,应该尽量掩盖事实,即西装和军衔已尽可能实现为short


public static String rankAsString(int __rank){
    return ranks[__rank];
}

public static String suitAsString(int __suit){
    return suits[__suit];
}



Java社区对此问题感到困惑,是否应该纯粹出于调试原因而重写toString()方法,还是应在“业务逻辑”中使用它。在这个“简单”的应用程序中,我认为您无需区分这两种用途,因此我将删除printCard(),而仅使用toString()

BTW,习惯上在方法修饰符之前有注释。


public @Override String toString(){
    return rank + " of " + suit;
}

// Print card to string
protected String printCard(){
    return ranks[rank] + " of " + suits[suit];
}



除了实现自己的方法外,重写equals()(或至少使其成为实例方法)可能是一个好主意。如果像我之前建议的那样使Card不可变,则它简化了比较参考以查看参考是否相同的实现,因为每个可能的卡只能有一个实例。

public static boolean sameCard(Card card1, Card card2){
    return (card1.rank == card2.rank && card1.suit == card2.suit);
}


(尽管比较等级和西服可能会更安全。)


编辑1:

首先是关于枚举的快速题外话。枚举有一个序数和一个compareTo方法,使您可以对它们进行排序。您还可以为它们分配属性,并根据这些属性创建自己的顺序。

官方语言指南提供了一些示例,这些示例适用于西装和等级枚举,以及使用行星作为示例扩展具有您自己的属性的枚举:http: //download.oracle.com/javase/1.5.0/docs/guide/language/enums.html

何时/如果我获得手排名(我还没看过)我也许可以提出一些建议,以通过枚举来实现它。


接下来是Comparator。我对它们没有太多经验,所以我只能提出一些一般性建议:


类应始终以Java中的大写字母开头。
您应该扩展它们从Comparator<Card>而不是Comparator<Object>开始,因为您只需要彼此比较卡,而不需要与其他任何对象进行比较。一般而言(尤其是德州扑克)。西装永远不会有通常仅在某些“元”上下文(例如,随机确定按钮的位置)中才需要的手排序,而当前不适用于您的程序。但是,如果您保留它,则应该更正西装的顺序,因为官方排名是(从最低到最高)“俱乐部”,“钻石”,“心脏”和“黑桃”。


接下来是董事会。首先,我想说的是,我不确定在现实世界的扑克应用程序中是否会使用这样的Board类。但是,从我的头顶上,我想不出其他方法来做这件事,并且在实践中,这是完全可以的。

我唯一要改变的是,而不是通过索引显式设置每张卡使用setBoardCard(Card card, int cardNum)时,我将让Board类本身在内部跟踪索引,而仅使用addBoardCard(Card card),因为您不应该“返回”并更改板卡(刻录卡的同上)。


编辑2:

关于分类服:好的,这很有意义。我还没看过手工评估。但是,更多的是将这种排序分组,因此也许有另一种(更好的)方式来做到这一点。我必须考虑一下。


跟踪索引:您当然可以使用Collection(或更具体地说,是List)来执行此操作(它会更像“类似于Java” ”,但如果您的主板上有固定的最大卡数,则阵列就可以了。我会这样:

@Override public boolean equals(Object that) {
  return this == that;
}



接下来是Deck

首先,我建议静态地仅创建一个Random对象,而不是为shufflecutDeck的每个调用都创建一个。

真正的问题是创建一个新的临时Deck对象,用于切割牌组,这可能会很快出错,因为它包含不必要的第二组卡片,如果有错误,您很容易会得到重复的卡片,而只需使用一个新的数组即可。使用System.arraycopy可以简化从一个阵列到另一个阵列的复制。

编辑3:

创建新的Deck不仅会创建一个新的数组,还会创建一个填充的数组用新的ca rds,您不需要。只需一个数组就足够了:

public class Board { //abbreviated

    private Card[] board = new Card[5];
    private Card[] burnCards = new Card[3];

    private int boardIndex = 0;
    private int burnCardIndex = 0;

    //methods
    protected void addBoardCard(Card card){
        this.board[boardIndex++] = card;
    }

    protected void addBurnCard(Card card){
        this.burnCards[burnCardIndex++] = card;
    }
}



编辑4:

关于Player没什么好说的,除了我删除了setCard只是使用构造函数将卡分配给玩家以使对象不可变。或至少像addCard中那样实现Board方法。


主类:

getNumberOfPlayers中,您的错误处理有些不一致。一方面,您写给System.out(可能更好地使用System.err),另一方面,您引发异常。在较大的项目中,将其“包装”到您自己的Exception类中可能是有意义的:

protected void cutDeck(){
    Card[] temp = new Card[52];
    Random random = new Random();
    int cutNum = random.nextInt(52);

    System.arraycopy(this.cards,      0, temp, 52-cutNum,   cutNum);
    System.arraycopy(this.cards, cutNum, temp,         0, 52-cutNum);

    this.cards = temp;
}


被捕获的IOException和无效范围都应该抛出相同的错误(或相关)自定义异常。不要仅仅抛出一个简单的getNumberOfPlayers,因为它对需要抓住它的其他人毫无意义。示例:

try { 
   userInput = br.readLine(); 
} catch (IOException ioe) { 
   throw new HoldemIOException(ioe);
}


请注意,在引起原因的NumberFormatExceptionException中,如果需要进一步的处理,将它们作为新异常的参数传递。 >
IOExceptionNumberFormatException都可以从基本的HoldemIOException扩展而来,后者又扩展了HoldemUserException。一个简单的“空”扩展,例如

try {
  intPlayers = Integer.parseInt(userInput);
} catch (NumberFormatException nfe) {
  throw new HoldemUserException("Error: Not an integer entered for number of players", nfe);
}

if ((intPlayers<1) || (intPlayers>9)){
  throw new HoldemUserException("Error: Number of players must be an integer between 1 and 9");
}


,这三种情况就足够了。一个自我抛出的错误)只是在最后完全未处理掉。在合理的位置(在您的情况下)在HoldemException处捕获所有已知的异常:

class HoldemException extends Exception {}


我仅添加了Exception循环,以显示如何处理这两种类型例外情况有所不同。为用户添加一个退出循环的适当方法将是明智的。


处理卡:

在这里,我们还有另一个计数器(getNumberOfPlayers)来跟踪平台的“位置”。同样,最好让do while类跟踪已发行的卡。您应该考虑将Deck实现为实际的“堆栈”或“队列”-无关紧要,因为您没有添加任何项目。 Java提供了可以使用的cardCounter接口。考虑一下,您还可以对DeckQueue使用相同的接口(尽管在这种情况下,您需要将烧录卡分离为自己的对象)。这样可以简化对PlayerBoardplayer.add(deck.remove());的处理。


编辑5:

好吧,很可能是最终编辑。

我已经开始研究人工评估,但我认为我不能为此写太多。您已经基于当前Card对象以非常有程序性的方式实现了它,如果您的目标是以更Java的方式实现它,则可能需要重新编写Card对象并首先创建一个合适的“ Hand”对象(最有可能基于board.add(deck.remove());),然后根据该结果重新编写评估。

扑克手评估是一个非常复杂的主题,尤其是当考虑到7张纸牌中的5张时。将取决于您是否要专注于“ Java良好实践”或“速度”。如果您真的有兴趣扩大此范围,那么您可能首先应该阅读该主题-关于Stack Overflow的几个问题,以及网上可能有无数的文章-然后重新发布一个新的问题,重点是手工评估。如果有时间,我会很高兴看到这一天。

只有一件事:一个,两个,三个和四个常数是什么?即使对于程序方法,这些似乎也完全不合适,应该很可能在使用它们的地方被适当的循环所代替。


最后,祝您玩得开心,好运爪哇土地冒险!

评论


\ $ \ begingroup \ $
@RoToRa:谢谢,我将尝试将我的回复发布为个人评论。 RE:导入我将java.util。*更改为java.util.Comparator
\ $ \ endgroup \ $
–user2733
2011年3月22日22:00

\ $ \ begingroup \ $
RE枚举:我本来确实拥有像枚举一样的等级和花色,但是当我开始思考需要如何按等级和花色对我的牌进行排序时,我将它们切换为空值,所以我不知道枚举是否会导致HandEval.class的排序问题,但是我知道在一定程度上可以解决问题,而且我不想走得太远,以至于如果以后不得不切换它,将需要大量的重构。
\ $ \ endgroup \ $
–user2733
2011-3-22在22:02



\ $ \ begingroup \ $
RE:按西装排序。由于皇家同花顺,我发现我在西装和排名上都需要比较器。例如,如果我有7h-8h-8s-9h-9c-10h-Jh。我需要一种对这些心进行排序的方法,以便可以检查连续的7 8 9 10 J心,如果仅按等级对心进行评估,则评估将失败。一件西装没有比其他西装具有更高的优先级,只是使估价容易。
\ $ \ endgroup \ $
–user2733
11 Mar 23 '11 at 13:12

\ $ \ begingroup \ $
在内部重新跟踪索引-您是否有标准的方法?是Collection 的吗?如果您有资源或执行此操作的标准方式,我会很感兴趣。再次感谢。
\ $ \ endgroup \ $
–user2733
2011年3月23日下午13:13

\ $ \ begingroup \ $
Re:内部索引,我真的很喜欢这个想法。今天,我将尝试实现该功能,并对洗牌和裁切套牌使用统一的Random对象。我不明白您只为cutDeck创建另一个数组的意思,创建临时甲板确实会创建另一个要使用的数组吗?
\ $ \ endgroup \ $
–user2733
2011-3-24在13:58

#2 楼

请考虑将TexasHoldem类及其所有逻辑(玩家,计数器,...的数量)与初始化方式分开。

您的主类将进入TexasHoldemProgram类,该类实例化TexasHoldem类,并且设置例如在main中输入的玩家数量。

这种做法称为“模型视图控制器”模式。通过将游戏的逻辑与交互的逻辑分开,您以后可以使用完全不同的GUI重用该类。您可能也应该将其应用于代码的其他部分,但我尚未对其进行全面研究。如果我发现其他答案中未提及的其他值得提及的内容。探索Java祝您好运!

评论


\ $ \ begingroup \ $
我对60,000英尺高度的MVC有所了解,但是我不确定我如何在这里实现它。我是否将创建另一个类,其唯一目的是创建TexasHoldem对象?如果您能解释一下,我实际上非常感兴趣,一旦我掌握了逻辑部分,我确实想为该程序实现一个用户界面。因此,我现在可以奠定的任何基础都将使我以后更轻松地工作。
\ $ \ endgroup \ $
–user2733
2011年3月23日20:19在

\ $ \ begingroup \ $
我从您的代码中注意到,您确实了解如何分离代码。 MVC更进一步,将模型从“控制器”的视图中分离出来。我可以在这里写一个广泛的答案,但是其他人已经在我之前做过(最好添加一下)。我建议您总体上熟悉设计模式,因为MVC是复合模式。我极力推荐Head First设计模式。这是一本非常有趣且有用的文章。如果您已经知道策略和观察者模式,则可以直接进入MVC。
\ $ \ endgroup \ $
–史蒂文·杰里斯(Steven Jeuris)
2011年3月23日在20:45