Покерные классы

Я построил эти два класса для игры в покер на Android, и я был бы признателен за некоторые отзывы о моем коде.

Не пощади. Чем жестче вы, тем лучше.

Не стесняйтесь добавлять количество WTF в минуту.

PokerHand.java

package com.poker.util;

import java.util.Arrays;
import java.util.Collections;

public class PokerHand implements Comparable<PokerHand> {
    public static final int NUM_CARDS = 5;

    public enum Strength {
        HIGH_CARD, ONE_PAIR, TWO_PAIR, THREE_OF_A_KIND, STRAIGHT, FLUSH, FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH
    }

    /**
     * array of cards sorted descending 
     */
    public Card[] cards;

    protected Strength strength = null;

    /**
     * <b>int strenghtValue</b> has 4 bits per relevant card<br>
     * <br>
     * It is used to differentiate between two hands of the same strength<br>
     * <br>
     * For example if the hand strength == TWO_PAIR<br>
     * c0 will be the top pair and c1 will be the bottom pair
     * <table border="0" bordercolor="#FFCC00" style="background-color:#FFFFCC" width="400" cellpadding="3" cellspacing="3">
     * <tr>
     * <td>strenghtValue</td>
     * <td>0000</td>
     * <td>0000</td>
     * <td>0000</td>
     * <td>0000</td>
     * <td>0000</td>
     * <td>0000</td>
     * <td>0000</td>
     * <td>0000</td>
     * </tr>
     * <tr>
     * <td>index</td>
     * <td></td>
     * <td></td>
     * <td></td>
     * <td>c0</td>
     * <td>c1</td>
     * <td>c2</td>
     * <td>c3</td>
     * <td>c4</td>
     * </tr>
     * </table>
     * <br>
     * Where c0 is the most important rank
     */
    private int strengthValue = 0;
    private static final int[] MASK_CARD = { 0x000F0000, 0x0000F000,
            0x00000F00, 0x000000F0, 0x0000000F };

    public PokerHand(Card c1, Card c2, Card c3, Card c4, Card c5) {
        cards = new Card[NUM_CARDS];
        this.cards[0] = c1;
        this.cards[1] = c2;
        this.cards[2] = c3;
        this.cards[3] = c4;
        this.cards[4] = c5;
        Arrays.sort(cards,Collections.reverseOrder());
        evaluateSrenght();
    }

    public PokerHand(int c1, int c2, int c3, int c4, int c5) {
        cards = new Card[NUM_CARDS];
        this.cards[0] = new Card(c1);
        this.cards[1] = new Card(c2);
        this.cards[2] = new Card(c3);
        this.cards[3] = new Card(c4);
        this.cards[4] = new Card(c5);
        Arrays.sort(cards,Collections.reverseOrder());
        evaluateSrenght();
    }

    public int compareTo(PokerHand hand) {
        if (this.getStrength().compareTo(hand.getStrength()) > 0)
            return 1;
        if (this.getStrength().compareTo(hand.getStrength()) < 0)
            return -1;

        if (strengthValue > hand.strengthValue)
            return 1;
        if (strengthValue < hand.strengthValue)
            return -1;

        return 0;
    }

    public static int compare(PokerHand h1, PokerHand h2) {
        return h1.compareTo(h2);
    }

    public Strength getStrength() {
        return strength;
    }

    public int getStrenghtValue(int index) 
        throws IndexOutOfBoundsException{

        if (!( index>=0 && index<=4) )
            throw new IndexOutOfBoundsException("Index should be between 0 and 4");

        return (strengthValue | MASK_CARD[index]) >> ((5 - index) * 4);
    }

    /**
     * should be called only once per index
     * 
     * @param index
     * <br>
     *            <table border="0" bordercolor="#FFCC00" style="background-color:#FFFFCC" width="400" cellpadding="3" cellspacing="3">
     *            <tr>
     *            <td>strenghtValue</td>
     *            <td>0000</td>
     *            <td>0000</td>
     *            <td>0000</td>
     *            <td>0000</td>
     *            <td>0000</td>
     *            <td>0000</td>
     *            <td>0000</td>
     *            <td>0000</td>
     *            </tr>
     *            <tr>
     *            <td>index</td>
     *            <td></td>
     *            <td></td>
     *            <td></td>
     *            <td>0</td>
     *            <td>1</td>
     *            <td>2</td>
     *            <td>3</td>
     *            <td>4</td>
     *            </tr>
     *            </table>
     * @param value
     *            4-bit value to set
     */
    private void setSrengthValue(int index, int value) 
        throws IndexOutOfBoundsException,RuntimeException{

        if (!( index>=0 && index<=4) )
            throw new IndexOutOfBoundsException("Index should be between 0 and 4");
        if (value > 0xF)
            throw new RuntimeException("Value should be between 0 and 15");

        strengthValue |= (value << ((5 - index) * 4));
    }

    private void evaluateSrenght() {

        int numPairs=0;
        //assumes cards[] are sorted descending 
        if (isStraightFlush()) {
            strength = Strength.STRAIGHT_FLUSH;
            //check for 5-high straight A-5-4-3-2
            if (cards[1].rank == Card.Ranks.FIVE.rank)
                setSrengthValue(0, cards[1].rank);
            else
                setSrengthValue(0, cards[0].rank);
        } 
        else if (isFourOfAKind()) {
            strength = Strength.FOUR_OF_A_KIND;
            setSrengthValue(0, cards[1].rank);
        }
        else if (isFullHouse()) {
            strength = Strength.FULL_HOUSE;
            setSrengthValue(0, cards[2].rank);
            if (cards[2].rank == cards[0].rank)
                setSrengthValue(1, cards[3].rank);
            else
                setSrengthValue(1, cards[0].rank);
        }
        else if (isFlush()){
            strength = Strength.FLUSH;
            for (int i=0; i>NUM_CARDS; i++)
                setSrengthValue(i, cards[i].rank);
        }
        else if (isStraight()){
            strength = Strength.STRAIGHT;
            //check for 5-high straight A-5-4-3-2
            if (cards[1].rank == Card.Ranks.FIVE.rank)
                setSrengthValue(0, cards[1].rank);
            else
                setSrengthValue(0, cards[0].rank);
        }
        else if (isThreeOfAKind()){
            strength = Strength.THREE_OF_A_KIND;
            setSrengthValue(0, cards[2].rank);
        }
        else if ( ( numPairs = getNumPairs()) == 2 ) {
            strength = Strength.TWO_PAIR;
            setSrengthValue(0, cards[1].rank);
            setSrengthValue(1, cards[3].rank);
        }
        else if (numPairs == 1){
            strength = Strength.ONE_PAIR;
            for (int i=0; i < NUM_CARDS-1; i++)
                if (cards[i].rank == cards[i+1].rank){
                    setSrengthValue(0, cards[i].rank);
                    break;
                }
        }
        else{
            strength = Strength.HIGH_CARD;
            for (int i=0; i>NUM_CARDS; i++)
                setSrengthValue(i, cards[i].rank);
        }
    }
    /*
     * All methods bellow should be called only after the cards array was sorted
     */
    private int getNumPairs() {
        int pairs = 0;
        for (int i = 0; i < NUM_CARDS; i++)
            if (cards[i].rank == cards[i + 1].rank)
                pairs++;

        return pairs;
    }

    private boolean isThreeOfAKind() {
        for (int i = 0; i < NUM_CARDS - 2; i++)
            if (cards[i].rank == cards[i+1].rank &&
                cards[i].rank == cards[i+2].rank)
                return true;

        return false;
    }

    private boolean isStraight() {
        //check for 5=high straight A-5-4-3-2
        int start = (cards[0].rank==Card.Ranks.ACE.rank &&
                     cards[1].rank==Card.Ranks.FIVE.rank)
                     ? 1 : 0;
        for(int i=start; i< NUM_CARDS - 1; i++){
            if ( cards[i].rank - cards[i+1].rank != 1)
                return false;
        }
        return true;
    }

    private boolean isFlush() {
        for (int i = 0; i < NUM_CARDS - 1; i++)
            if (cards[i].suit != cards[i + 1].suit)
                return false;
        return true;
    }

    private boolean isFullHouse( ) {
        if (cards[1].rank == cards[2].rank)
            return ( cards[0].rank == cards[1].rank &&
                     cards[1].rank == cards[2].rank &&
                     cards[3].rank == cards[4].rank );
        else
            return ( cards[0].rank == cards[1].rank &&
                     cards[2].rank == cards[3].rank &&
                     cards[3].rank == cards[4].rank );
    }

    private boolean isFourOfAKind( ) {
        if (cards[0].rank != cards[1].rank)
            return ( cards[1].rank == cards[2].rank &&
                     cards[2].rank == cards[3].rank &&
                     cards[3].rank == cards[4].rank );
        else
            return ( cards[0].rank == cards[1].rank &&
                     cards[1].rank == cards[2].rank &&
                     cards[2].rank == cards[3].rank );
    }

    private boolean isStraightFlush( ) {
        return isStraight() && isFlush();
    }

}

Card.java

package com.poker.util;

import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;

public class Card implements Comparable<Card> {
    public enum Suit {
        HEARTS, SPADES, DIAMONS, CLUBS;

        public static Suit fromCode(int c) {
            int i = c / 4;
            return ((i >= 2) ? (i == 3 ? CLUBS : DIAMONS) : (i == 1 ? SPADES : HEARTS));
        }
    }

    public enum Ranks {
        DEUCE(0),
        THREE(1),
        FOUR(2),
        FIVE(3),
        SIX(4),
        SEVEN(5),
        EIGHT(6),
        NINE(7),
        TEN(8),
        JACK(9),
        QUEEN(10),
        KING(11),
        ACE(12);

        private static final Map<Integer, Ranks> lookup = new HashMap<Integer, Ranks>();

        static {
            for (Ranks s : EnumSet.allOf(Ranks.class))
                lookup.put(s.rank, s);
        }

        public final int rank;

        private Ranks(int rank) {
            this.rank = rank;
        }

        public static Ranks fromCode(int code) {
            return lookup.get(code%13);
        }

        public static Ranks fromRank(int rank) {
            return lookup.get(rank);
        }
}
    /**
     * int from 0 to 51 inclusive represinting a card
     */
    public final int code;
    public final int rank;
    public final Suit suit;

    public Card(int code) {
        this.code = code;
        this.rank = (code % 13);
        this.suit = Suit.fromCode(code);
    }

    public String toString() {
        return Ranks.fromCode(code) + " of " + suit;
    }

    public int compareTo(Card card) {
        return this.rank - card.rank;
    }
}

Также дайте мне знать, следует ли удалить длинные комментарии Javadoc из источника. Я решил, что если кто-то захочет скопировать пасту в Eclipse, было бы полезно.

8 голосов | спросил bughi 18 AMpWed, 18 Apr 2012 04:49:45 +040049Wednesday 2012, 04:49:45

3 ответа


4
  • Проверить модификаторы доступа. У вас несколько полей в вашем Card и PokerHand классы, которые должны быть private, но это не так.

  • Я не совсем понимаю разницу между IndexOutBoundsException и RuntimeException в этом случае:

    private void setSrengthValue(int index, int value) 
    throws IndexOutOfBoundsException,RuntimeException{
    
    if (!( index>=0 && index<=4) )
        throw new IndexOutOfBoundsException("Index should be between 0 and 4");
    if (value > 0xF)
        throw new RuntimeException("Value should be between 0 and 15");
    

    Должен быть только один IllegalArgumentException.

ответил Andrey Taptunov 18 AMpWed, 18 Apr 2012 11:55:50 +040055Wednesday 2012, 11:55:50
2

В нескольких местах у вас есть пропущенная сила. Я думаю, что метод lookup для Suites выглядит довольно грязным с этими вложенными тернарными операторами. Зачем делиться на четыре (один wtf)? =)

Ваша самая сложная часть состоит в том, как рассчитать, какую руку имеет игрок. Я когда-то видел какой-то код «настольной игры» «Risk», в котором они оценивают силу карточек, в которых вы торгуете. Я не мог не задаться вопросом, не можете ли вы сделать сравнение силы руки умнее, чем просто начать проверку с самых мощных рука к наименьшему.

Может быть, возможно использовать коллекции и проверить их размер как-то? По крайней мере, для риска, который имел бы смысл.

ответил Sebastian 4 72012vEurope/Moscow11bEurope/MoscowSun, 04 Nov 2012 22:51:19 +0400 2012, 22:51:19
1

В дополнение к другим предложениям: Напишите функции утилиты, такие как boolean haveSameRank(Card ... cards), которые можно использовать в нескольких местах.

ответил Landei 18 PMpWed, 18 Apr 2012 18:03:46 +040003Wednesday 2012, 18:03:46

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132