2013-04-15 170 views
0

我正在設計一個撲克遊戲。將有一個PokerHand類用戶卡(總是5張卡)。 PokerHand有不同的類別,例如直線,沖洗,滿屋等比較沒有RTTI的抽象類?

現在我想要所有的PokerHand都是可比的。有一個定義的類別之間的順序:直衝>一種>滿屋> ...對於每個類別都有一個獨特的比較規則。例如。對於Straights,高牌決定。對於「4種」,4張相同的牌決定。

class PokerHand { 
public: 
    int CompareTo(const PokerHand* another) = 0; 
    Category GetCagegory(); 
... 
} 

有了RTTI,我可以實現的CompareTo作爲

class Straight : public PokerHand { 
    ... 
} 

int Straight::CompareTo(const PokerHand& another) OVERRIDE { 
    const Straight* s = dynamic_cast<const Straight*>(another); 
    if (s == NULL) { 
    // Not a straight. Compare category. 
    ... 
    } else { 
    // compare high card 
    ... 
    } 
} 

現在的問題是,考慮RTTI大多以「不建議使用」治療,有沒有落實不比較的好方法使用RTTI?

+0

你可以有一個包含類的虛擬功能,但我想你會了解它的錯誤的方式......我會寫一個答案到那種程度。 –

+0

爲各種不同的撲克牌手分別創建一個類似乎是一個糟糕的主意。有很多這樣的東西,它們重疊。防爆。皇家同花順,同花順,只是簡單的沖洗。 – seand

+0

[什麼時候應該使用訪問者設計模式?](http://stackoverflow.com/questions/255214/when-should-i-use-the-visitor-design-pattern) –

回答

1

您可以爲每種手型和重量分配顏色和卡片順序的重量。然後你可以有一個虛擬函數來計算權重和重量,並比較結果。這對你有用嗎?

+0

可能的重複實際上沒有任何原因功能是虛擬的。真的只有一種類型的手(目前)。 –

+0

這並不是我得到的印象。你有一個(皇家/直線)沖洗,4種,一個滿屋,一對,等等。這些在開場白中是不同的。當然,你可以很容易地做到這一點,但我的答案與「現狀」相關。 –

+0

一隻手是否是平齊的,或者直的,或者其他什麼,不是(或者不應該是)類型的一部分;這是手的價值的函數。只要他將自己的遊戲限制在五張牌上,就不需要任何虛擬功能。 –

1

儘管它是誘人的,但鑑於清晰,直接等與撲克手之間的關係,我實際上不會在這裏使用繼承,至少不適用於手型。在任何抽獎撲克遊戲中,例如,手牌的類型可以更改爲,而在其他遊戲如德州撲克遊戲中,它只是逐漸顯露出來。但是,當然類類型在初始化後不能改變。

只是儲存卡片,並有一個基本或朋友函數返回類型(一個枚舉的成員)和另一個用於訂購卡片(所以你可以得到高卡等)然後定義一個簡單的比較器函數,再次比較兩隻手的基類或全局朋友。

struct Card 
{ 
    int suit, rank; 
}; 
bool operator<(const Card& a, const Card& b) { ... } 

class PokerHand 
{ 
    public: 
     // ... constructor 

     enum HandType 
     { 
     NOTHING = 0, 
     PAIR, 
     TWO_PAIR, 
     ... 
     } 

     HandType GetHandType() { ... } 

    private: 
     std::vector<Card> _hand; 
}; 
bool operator<(const PokerHand& a, const PokerHand& b) { ... } 

不罷工,難以填補空白。

如果你是當然你想要派生類,那麼我會去與類型字段在RTTI,這可以通過例如。如上所述的枚舉。

0

這應該很簡單。您可以添加某種重量:

class PokerHand { 
public: 
    //... 
    virtual int GetHandWeights() const = 0; 
}; 

bool operator<(const PokerHand & lh, const PokerHand & rh) 
{ 
    return lh.GetHandWeights() < rh.GetHandWeights(); 
} 

然後,您只需使用operator<即可。

2

我很確定你這樣做的方式是錯誤的。

A PokerHand是一個PokerHand,它是否持有滿屋,同花順或一組完全無用的卡。 [你可能會發現,如果你用五張牌,七張牌,或者顯示或者不顯示你的牌等等來玩撲克,但是爲了評估你的手是否「值得」,你需要一種類]。

你需要的是一個函數,可以告訴你實際上有什麼。要做到這一點,我會假設你有一個struct Card包含以下內容:

struct Card 
{ 
    int suite; (1..4) 
    int value; (2..14) 
}; 

那麼,我想我們有5張牌打,如果您正在使用的卡的數量可變的玩,那麼你probobably想要使用一個矢量。

class PokerHand 
{ 
    ... 
    Card cards[5]; 
} 


int PokerHand::value()  
// return 0 for "useless, nothing", otherwise how good -> better is higher 
{ 
    int ret = 0; 

    ... check if they are the same suite (flush) 
     ... if so, are they in sequence (straight flush) 
      ... if so, is the highest a king - (royal straight flush) 
     return ret; 

    else 

     ... here we write code to check how many cards have the same value 
      (2, 3, 4 of a kind or full house) 
     if at least two same value: 
     return ret;   

    return ret; 

} 

您可能會發現,如果您按照套件或兩個步驟的值分別對手進行排序,則可以更輕鬆地編寫此函數。你需要考慮卡的價值,例如你必須處理「同等價值,更好的套房」類型的情況,例如,並且使用剩餘卡的值(例如,3種具有兩個「未使用的卡」)來確定最高值。

這裏有上市規則: http://en.wikipedia.org/wiki/List_of_poker_hands

+0

關於'PokerHand :: value()',我可能會將它作爲一系列'if ... else if ... else if ...'來實現,按照rank排序檢查每個可能性。它可能不是最有效的(例如,你檢查'if(isStraightFlush())'和'if(isFlush())''中的flush,但它似乎是最簡單的編寫和理解。你也希望返回一個結構體,因爲你需要兩個元素:手的類型(例如flush,一種三種等等)以及類型中的等級。 –

+0

另一個可能適用繼承的地方是:計算類型內的等級。你可以爲每種類型設計一個等級計算器。 –

+0

我選擇單一返回值的原因是我想要一個簡單的比較 - 儘管我想我們總是可以有兩個函數,一個返回一個「它是什麼」的結構,一個是該類型中的一個等級,然後是第二個可以理解這些等級的功能。是的,一組執行'isFlush()'的函數肯定是一個好主意。 –