2016-06-30 2 views
1

Я знаю, что есть тонна вопросов об этой вневременной реализации, но, как новый программист ООП, я изо всех сил пытаюсь понять необходимые концепции, чтобы сделать какие-либо основания.Концептуальная сложность C++ Палуба карт

Я строю фактическую рандомизированную колоду в массиве, который будет играть роль колоды игровых карт для любой карточной игры? Или я «реплицирую» колоду случайных игральных карт, создавая 4 костюма, а затем 13 разных лиц? Я видел множество реализаций, и я не совсем понимаю, что они получают. int deck[]; - это то место, где я собирался хранить карты. Я бы заполнил массив колоды, когда был создан экземпляр класса колоды карт?

Мой главный только имеет функцию печати под названием (что я до сих пор не написано)

//Texas holdem build 
//Will attempt using Classes and inheritance 
//Full build for up to 6 players 

#include <iostream> 
#include "deckOfCards.h" 

int main() 
{ 

    DeckOfCards deck; 

    deck.printDeck(); 

    return(0); 
} 

Заголовок

* deckOfCards.h 
* 
* Created on: Jun 28, 2016 
*  Author: TAmend 
*/ 

#ifndef DECKOFCARDS_H_ 
#define DECKOFCARDS_H_ 

class DeckOfCards 
{ 

    public: 
     DeckOfCards(); 
     void printDeck() const; 
     void shuffle(); 

    private: 
     int currentCard; 
     int deck[]; 

}; 

#endif /* DECKOFCARDS_H_ */ 
+8

Ради обучения и выступая в качестве объектно-ориентированного программирования конструкций. «Палуба карт» будет контейнером «52 объекта», а не просто 'int'. Таким образом, другая небольшая структура/класс будет представлять собой «карточку». Что делает эта карта (класс)? Он имеет костюм (1 из 4), значение (1/13) и лицо (1/13). Тогда в вашем классе «Deck of cards» будет функция, которая будет заполнять 52 объекта этого маленького класса (карты) в свой собственный закрытый контейнер-член, гарантируя отсутствие дубликатов в карточках. –

ответ

2

Ну, имея Cardclass или struct и DeckOfCards класс, который действует как специализированный контейнер является правильный путь (как было указано в @Thomas' answer):

struct Card 
{ 
    enum Suit_Type { 
     Diamonds, 
     Hearts, 
     Spades, 
     Clubs, 
    } suit; 
    enum Value_Type { 
     Two = 2, // <<<<<<<<< Note starts at 2 
     Three , 
     // Four, Five, Six, aso. ... 
     Ten , 
     Jack , 
     Queen , 
     King , 
     Ace , // <<<<<<<<< Note has the highest value here 
    } value; 
    void printCard(); 
}; 

void Card::printCard() { 
     switch(suit) { 
     case Hearts: 
      std::cout << "♥"; 
      break; 
     case Diamonds: 
      std::cout << "♦"; 
      break; 
     case Clubs: 
      std::cout << "♣"; 
      break; 
     case Spades: 
      std::cout << "♠"; 
      break; 
     } 
     if(value < Jack) { 
     std::cout << (int)value; 
     } 
     else { 
      switch(value) { 
      case Jack: 
       std::cout << 'J'; 
       break; 
      case Queen: 
       std::cout << 'Q'; 
       break; 
      case King: 
       std::cout << 'K'; 
       break; 
      case Ace: 
       std::cout << 'A'; 
       break; 
      } 
     } 
    } 

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

bool operator<(const Card& lhs, const Card& rhs) { 
     return (lhs.suite < rhs.suite) && 
       (lhs.value < rhs.value); 
    } 

    bool operator>(const Card& lhs, const Card& rhs) { 
     return (lhs.suite > rhs.suite) && 
       (lhs.value > rhs.value); 
    } 

Обратите внимание, что выполнение теста равенства не имеет большого смысла с семантическим точки зрения, если вы не хотите играть с несколькими DeckOfCards одновременно.

Как Cards должен вести себя в определенной игре, может быть полностью делегирован классу Strategy Pattern.


DeckOfCards может быть инициализирована из соответствующего списка инициализаторов:

class DeckOfCards { 
    DeckOfCards() : cards_({ 
     { Diamonds, Two } , 
     // ... 
     { Diamonds, Ace } , 
     { Hearts, Two } , 
     // ... 
     { Hearts, Ace } , 
     { Spades, Two } , 
     // ... 
   { Spades, Ace } , // !!! Extremely important !!!
  { Clubs, Two } , 
     // ... 
     { Clubs, Ace } , 
    }) {} 

    void printDeck(); 
    void shuffle(); 

private: 
    std::array<Card,52> cards_; 
}; 

все остальные функции могут быть реализованы легко, как то:

void DeckOfCards::printDeck() { 
    bool first = true; 
    for(auto card : cards_) { 
     if(!first) { 
      std::cout << ", "; 
     } 
     card.printCard(); 
     first = false; 
    } 
    std::cout << std::endl; 
} 

void DeckOfCards::shuffle() { 
    std::random_device rd; 
    std::mt19937 g(rd()); 

    std::shuffle(cards_.begin(), cards_.end(), g); 
}; 

Я не 100% уверен, что вы хотите достичь с currentCard члена в DeckOfCards, но я полагаю, вы wan't, что быть смещение к следующему Card раздавать из DeckOfCards, так что вы можете просто использовать его в качестве индекса для cards_ массива, чтобы раздать ссылку на подстилающей Card, например, и увеличиваем его впоследствии:

const Card& getNextCard(bool& cardsAvailable) { 
     cardsAvailable = true; 
     if(currentCard < 52) { 
      return cards_[currentCard++]; 
     } 
     // Reset the deck 
     cardsAvailable = false; 
     currentCard = 0; 
     shuffle(); 
} 

Go найти пасхальное яйцо

+0

Я никогда не слышал, чтобы клубы назывались «крест». Кроме того, значение туза зависит от игры. В некоторых играх все лицевые карты имеют одинаковое значение. –

+0

@RobK THX для понимания, я не носитель языка и получил это с сайта перевода. Ну, конечно, порядок ценностей зависит от реальной игры, но большинство карточных игр используют этот порядок (небольшая коррекция в сюитах). –

+0

В большинстве мест вы используете 'Deck', но класс определяется как' DeckOfCards'. Я предполагаю, что это просто ошибка копирования/вставки. –

1

ответил я это раньше, так что я буду делать это снова.

ИМХО, есть два объекта: контейнер карт и карт. Не смешивайте их.

Начнем с карты. Карта имеет масть и значение:

struct Card 
{ 
    Suit_Type suit; 
    Value_Type value; 
}; 

Контейнер может быть что угодно, например, std::vector, std::list, или мой любимый std::deque. ;-)

typedef std::vector<Card> Deck_Of_Cards; 

Вы можете создать свой собственный контейнер, но для большинства заданий с использованием карточек вам не нужно. Предпочитают существующую структуру данных контейнера.

Что касается типов внутри структуры Card, вопрос предпочтения. Вы можете использовать перечисление, строку или что-то еще для Suit_Type. Аналогично с Value_Type.

Чтобы сделать карты более удобным, вы должны реализовать следующие методы в Card структуры:

  1. Конструкторы, операторы присваивания, деструктор.
  2. Операторы равенства и заказа (например, == и <)
  3. вставки и извлечения потока (например, >> и < <)

Также рассмотрим функцию std::random_shuffle.

+4

_ «Я уже ответил на это, поэтому я сделаю это снова». Разве это не обман? –

+0

Я до сих пор не дал полного ответа, только предложения. :-) –

+0

Ну, теперь вы можете попробовать дать полный ответ (BTW, так как количество карточек в _деке обычно фиксировано, я бы предпочел рекомендовать 'std :: array <>' в качестве внутреннего типа контейнера) , –

0

Хорошо, только для того, чтобы сделать его максимально понятным, класс вашей колоды будет действовать как класс «контейнер». Это означает, что он будет держать кучу карт карточек типа; не int.

В конце концов, массив, который вы используете для хранения ваших карт, будет выглядеть примерно так: Card deck []; вместо int deck []; Это позволит вам добавить любые свойства, которые вам нравятся на каждой отдельной карте.

Вы можете рандомизировать каждое свойство класса карты при построении или непосредственно перед этим и передать случайные значения.

Ради помочь вам понять:

class Card 
{ 
public: 
    Card(int value): value(value) {} 
    int Getvalue(){ return value; } 
private: 
    int value; 
}; 



class DeckOfCards 
{ 

public: 
// DeckOfCards(); 
// void printDeck() const; 
    // void shuffle(); 
    void createDeck() 
    { 
     for(int i = 0; i < deck_size; i++) //Implementation of createDeck 
      deck[i] = new Card(rand()%10-1);//whatever val you want to generate 
    } 

private: 
// int currentCard; 
    // Card deck[]; 

}; 

Таким образом, вы можете захватить карты, когда вы хотите, и добавить любые свойства вы хотите, например, костюм.

ПРИМЕЧАНИЕ: вектор будет предпочтительнее примитивного массива, но не просто отбрасывает класс DeckOfCards, потому что если вы сделаете то, где вы храните функцию shuffledeck или функцию printdeck? и т. д. Вместо этого просто замените массив элементов вектором.

+3

_ «вектор предпочтительнее ...» _ Фактически, 'std :: array ' будет правильным внутренним стандартным контейнером тип. В этом случае нет необходимости в распределении динамической памяти. –

+0

@ πάνταῥεῖ Согласен 100% –

+0

Не было выяснено, какой тип карточной игры/колоды он должен быть, поэтому я пропустил свойство костюма. Кроме того, да, нормальный массив, выделяющий его члены из стека, будет прекрасным, но что, если вы хотите удалить элемент, опять же не выясняется, какой тип игры/колоды он есть. Вы можете использовать стандартный массив, все зависит от того, как вы хотите управлять удалением каждой карты из массива (если вообще). – Geoff

0

Это действительно зависит от того, чего вы хотите достичь своей колодой карт, как вы хотите ее использовать. В некоторых случаях простой int[] будет полностью достаточен для ваших нужд. В других вам понадобятся полные классы карт и колонок, а также другие вспомогательные классы.Реализации карты и колоды, приведенные в других ответах (невольно?), Специализируются на определенных карточных играх и совершенно непригодны для других. Не спрашивайте, что у вас есть, спросите себя, что вам нужно. Do the simplest thing that could possibly work.

(И действительно, этот вопрос слишком широко/мнение на основе и может быть больше дома, на programmers.stackexchange.com)

Смежные вопросы