Реализация колоды карт в C ++ - PullRequest
1 голос
/ 10 марта 2011

Итак, я пытаюсь создать колоду карт, и я все еще новичок в C ++ и указателях, поэтому у меня есть несколько вопросов

Итак, у меня есть класс Card с getRank, getSuit и сравнение двух Card объектов. Они устанавливают колоду 1-13 для ранга и 1-4 для масти. Таким образом, это простое сравнение, сравнивая ранг + масть одной карты с рангом + мастью другой карты.

Итак, я инициализировал и объявил два массива следующим образом:

char Rank[13] = {1,...13};
char Suit[4] = ...

и мои методы таковы:

char* getSuit(){ return Suit; }
char* getRank(){ return Rank; }
int Comp(Card *card) {
    if (rank+suit < card->rank+card->suit)
        return 1;
    else if...
    else ...
}

Мой вопрос: плохая идея иметь массив char, так как я храню только целые числа? Позже я планирую преобразовать эти числа в «Three Spade», поэтому я использовал char.

Мой другой вопрос: мои методы get выглядят правильно? Методы get, будут ли они возвращать весь массив или индекс массива, что я и хочу. И правильно ли я использую '->'?

Я все еще в процессе рисования, поэтому у меня есть только фрагменты кода

Ответы [ 8 ]

2 голосов
/ 10 марта 2011

-> получит значение элемента RHS объекта, на который ссылается LHS.Так что да, это правильно, если вы имеете дело с указателями на LHS.

Вы можете посмотреть на использование Enums для костюма.

Я рекомендую снова взглянуть на вашу логику для оценки как @littleadvсказал.

1 голос
/ 10 марта 2011

Вот пример, который вы можете рассмотреть и, возможно, построить на нем свой класс:

class Card
{
public:
   // TODO: provide suitable constructor...

   enum Suit {Hearts, Diamonds, Clubs, Spades};
   enum Rank {A, K, Q, J, _10, _9, _8, _7, _6, _5, _4, _3, _2};

   Suit getSuit() { return suit; }
   Rank getRank() { return rank; }

   // TODO: implement setters, etc...

   bool operator==(const Card& c) const
   {
      return rank == c.rank && suit == c.suit;
   }

private:
   Suit suit;
   Rank rank;
};

Поэтому я предлагаю вам использовать перечисления и использовать критерий точного сравнения для сравнения двух карт.
Точно так же вы можете реализовать operator> и operator <в соответствии с вашими правилами игры и логикой. </p>

У тебя есть идея ...

0 голосов
/ 01 октября 2014

Использование интерфейса

Он предоставляет студентам простой способ использовать карточки в коде, который они пишут, не имея доступа к внутренним частям карточки, не имея возможности создать конкретную карточку,и не зная, как реализованы карты.Этот процесс начинается с кода для интерфейса карты, интерфейса, который мы называем ICard.

public interface ICard extends Comparable
{
public static final int SPADES = 0;
public static final int HEARTS = 1;
public static final int DIAMONDS = 2;
public static final int CLUBS = 3;
public int getSuit();
public int getRank();
}

Интерфейс определяет поведение карты без предоставления информации о том, как реализованы карты.Как только они узнают, что getSuit() возвращает значение, подобное ICard.HEARTS, и что getRank() возвращает значение в диапазоне от 1 (туз) до 13 (король), студенты могут писать код из этой спецификации.Например, вот код, чтобы проверить, отсортирован ли массив карточек.Мы не знаем, как он был отсортирован (например, все ли тузы идут до двойки или все пики идут раньше сердец?), Но мы можем определить, что массив отсортирован.1 Начало имен интерфейсов с заглавной буквы I, за которой следует заглавное имя, является общим соглашением об именах в объектно-ориентированном программировании на многих языках, а не только на Java.

public boolean isSorted(ICard[] list){
for(int k=1; k < list.length; k++){
if (list[k-1].compareTo(list[k]) > 0){
return false;
}
}
return true;
}

Начиная с этого простого интерфейса ICard, мыможет задавать студентам множество вопросов для тестирования и анализа концепций, начиная с синтаксиса Java и заканчивая решением проблем с одной, двумя или несколькими картами.Здесь приведены некоторые простые примеры, а другие доступны на веб-сайте.Отвечая на эти вопросы, студенты должны понимать интерфейс, так как нет реализации.Студенты сосредотачиваются на поведении, а не на переменных экземпляра и других деталях реализации, таких как создание строки, представляющей туз пик.Вопросы ICard / Вопросы по коду

  1. Напишите функцию isRed, которая возвращает значение true, если ее параметр ICard имеет красный цвет (сердца или ромбы), а в противном случае возвращает значение false.public boolean isRed (ICard card) {…}

  2. Пара - это две карты одного ранга (например, два короля или две восьмерки).Напишите функцию isPair, которая возвращает true, если два ее параметра ICard представляют пару, и возвращает false в противном случае.public boolean isPair (ICard a, ICard b) {…}

  3. Флеш - это рука, скажем, в покере, в которой все карты имеют одинаковую масть (например, пять сердец,или пять клубов для пятикарточной раздачи).Напишите функцию isFlush, которая возвращает истину, если массив карточек сброшен, и возвращает ложь в противном случае.public boolean isFlush (ICard [] hand) {…}

  4. В блэкджеке или 21 значение руки - это общее количество карт, где валеты, дамы и короли (11), 12 и 13 соответственно, как возвращено getRank ()), каждый считается как 10, а туз считается как 1 или 10, в зависимости от того, что лучше.Всего более 21 это бюст;это не хорошо, чтобы разорить.Напишите функцию handTotal, которая возвращает общее значение руки.public int handTotal (ICard [] hand) {…} От интерфейса к реализации Интерфейс ICard предоставляет достаточно информации для написания кода о картах, но, например, нет способа создать массив карт или даже одну карту для тестированияфункции, написанные выше (например, isPair и handTotal).Откуда берутся карты?В большинстве реальных примеров карты приходят из колоды.Мы разработаем класс, который моделирует колоду - это, по сути, фабрика для создания и получения карт.Для простоты и поощрения изучения некоторых стандартных интерфейсов Java класс Deck будет реализовывать интерфейс java.util.Iterator.Например, чтобы сохранить все карты из колоды в переменную ArrayList, мы можем использовать следующий код:

    Deck d = new Deck ();ArrayList cards = new ArrayList ();while (d.hasNext ()) {ICard card = (ICard) d.next ();System.out.println (карта);cards.add (карта);} System.out.println ("# of cards detted =" + cards.size ());

Последние несколько строк, выведенных этим фрагментом кода, могут быть такими, как показано ниже.Они будут отличаться каждый раз, потому что разработанный здесь класс колоды перетасовывает карты, которые он сдает, путем итерации.… Туз пик пиковый дубль шесть пиков десять чearts десять из пиков число сданных карт = 52 Если мы поменяем строки после цикла следующим образом, выходные данные также изменятся.

Collections.sort(cards);
for(int k=0; k < cards.size(); k++){
System.out.println(cards.get(k));
}

System.out.println ("# раздач карт =" +cards.size ());Выходные данные показывают, как карты, возвращенные из класса Deck, реализуют интерфейс Comparable.… Девять клубов десять клубов джек клубов королева клубов король клубов кол-во карт сдано = 52 Полный код для колоды класса показан ниже.Методы hasNext (), next () и remove () необходимы для классов, которые реализуют интерфейс Iterator.Приведенный ниже код показывает, как создаются объекты типа Card.

public class Deck implements Iterator{
private ArrayList myCardList;
private int myIndex;
public Deck(){
myCardList = new ArrayList();
for(int suit = ICard.SPADES; suit <= ICard.CLUBS; suit++){
for (int rank = 1; rank <= 13; rank++){
myCardList.add(new Card(suit,rank));
}
}
shuffle();
}
private void shuffle(){
Collections.shuffle(myCardList);
myIndex = 0;
}
public boolean hasNext() {
return myIndex < myCardList.size();
}
public Object next() {
ICard card = (ICard) myCardList.get(myIndex);
myIndex++;
return card;
}
public void remove() {
throw new UnsupportedOperationException();
}
}

Объект Deck хранит 52 карты - эти карты можно получить из объекта Deck путем итерации, но объект Deck не может быть перетасован иповторно использовать.Вместо этого должен быть создан новый объект Deck для раздачи новых карт.Это упрощает работу и предоставляет простой для понимания пример класса, который реализует интерфейс Iterator.Метод remove () является необязательным --- для класса Deck, вызывающего этот метод, генерируется исключение.Изучение колод / вопросы по коду

  1. Непосредственно перед вызовом метода shuffle в конструкторе опишите порядок объектов, хранящихся в myCardList.

  2. Опишите, как меняется каждый метод Deck, если переменная экземпляра myCardList изменяется на массив объектов Card, например, private ICard [] myCardList;Какой выбор для myCardList лучше?Почему?

  3. Напишите клиентский код, который определяет объект Deck и создает массив из 13 объектов ICard, которые представляют пики, которые раздаются из колоды.Сделайте это, изучив каждый раздаемый объект и сохранив только карточки с лопатами.

  4. Напишите тело гипотетического конструктора класса Hand, указанного ниже

    private ArrayList myCards;/ **

    • раздача numCards от d, хранить в myCards
    • (предположим, что в d осталось хотя бы numCards) * / public Hand (колода d, int numCards){}

От колод до карт Нашей первоначальной задачей было использование интерфейса ICard, а не забота о том, как реализованы карты.Тем не менее, в какой-то момент должна быть реализация.Нетрудно утверждать, что объекты Card должны быть созданы классом Deck.Это подход, который мы использовали здесь.Класс Card - это закрытый класс, объявленный в классе Deck.На самом деле нет веской причины объявлять это в Deck (файл Deck.java).Однако, объявив его закрытым, мы делаем это невозможным для любого кода class2;его можно так же легко объявить как непубличный класс внутри методов, отличных от класса Deck, для создания объектов Card.Это помогает достичь нашей первоначальной цели.Клиентские программы могут получать карты из колоды, но не могут создавать карты.Поскольку колода снабжает объекты ICard, невозможно заменить карту, если она получена из колоды, поскольку интерфейс ICard не поддерживает модификацию карты.

Как написано, частный класс Card, определенный в колодеКласс также не поддерживает модификацию, поскольку его переменные экземпляра частного состояния являются окончательными, но это дополнительная защита, которая, вероятно, не требуется, поскольку ни один клиентский код не имеет доступа к закрытому классу Card.2 Обычно классы, объявленные в другом классе, часто ссылаются на состояние включающего объекта.В этом случае вложенный класс Card объявляется как закрытый статический класс, поэтому он не может ссылаться на закрытое нестатическое состояние внутри объекта Deck.Класс Card может ссылаться на статическое состояние колоды, но в этом коде его нет.Класс Card доступен на веб-сайте;мы не включаем его сюда, поскольку его реализация не имеет прямого отношения к нашему обсуждению дизайна.Внимательный читатель может утверждать, что наша первоначальная цель не была достигнута.Код клиента может обмануть, например, путем создания объекта Deck, а затем раздачи карт от этого объекта до туза пробелов (oлюбая другая карта).В текущем дизайне класса Deck это действительно так.Тем не менее, мы могли бы создать одноэлементный объект Deck таким же образом, как единственный экземпляр класса Random используется в тематическом исследовании морской биологии.Объекты Singleton обычно создаются путем объявления конструкторов, чтобы они были частными.В этом случае конструктор Deck изменится с публичного на приватный.Клиентский код получает Deck, вызывая открытый метод getInstance (), который возвращает закрытый статический объект Deck, хранящийся в классе Deck.Метод getInstance создает этот закрытый объект при первом вызове getInstance.

0 голосов
/ 10 марта 2011

Карта - плохой кандидат в класс - у нее нет поведения, следовательно, нет методов. Так что лучше смоделировать как структуру. Карты являются неизменяемыми (если вы не обманываете), поэтому указаны постоянные данные участника:

enum Suit {Hearts, Diamonds, Clubs, Spades};
enum Rank {A, K, Q, J, _10, _9, _8, _7, _6, _5, _4, _3, _2};

struct Card
{
    Card(Suit suit, Rank rank) : suit(suit), rank(rank) {}

    const Suit suit;
    const Rank rank;
};

Если вы можете жить с синтаксисом card.first вместо card.suit, вы получите его бесплатно, используя стандартную пару:

#include <utility>
typedef const std::pair<Suit, Rank> Card;

Card aceOfSpades(Spades, A);

Бонус: Вы также получаете разумных операторов == и <бесплатно. </p>

0 голосов
/ 10 марта 2011

Этот вид дискриминационного союза лучше всего обрабатывать на языках семьи ML.

Например, в OCaml:

type suit = Hearts | Diamonds | Clubs | Spades
type rank = Ace | King | Queen | Jack | Num of int
type card = rank * suit

Да, я знаю, автор попросил ответить на C ++ ...

0 голосов
/ 10 марта 2011

Вы начинаете строить свой класс постепенно с рабочим кодом.Начните с простого класса, который имеет только метод getSuit и getRank.Напишите небольшое приложение, которое тестирует его, например, так:

int main() {
    Card card(10, 4);

    if (card.getSuit() != 4) {
        std::cout << "Wrong suit!" << std::endl;
    }

    return 0;
}

Написав такой небольшой тест для каждой реализуемой вами функции, вы убедитесь, что все работает.Кроме того, если вы сначала подумаете о том, как вы хотите использовать класс, вы лучше поймете реализацию.

О фактической реализации многое зависит от того, чему учат в вашем классе.Простая вещь, которую нужно рассмотреть, - это представить ряды и масти, используя enum.

0 голосов
/ 10 марта 2011

Благодаря этому процессу сравнения вы в конечном итоге получите равные карты ... что, я думаю, неправильно ... Изменить: также есть стартовый набор блэкджек в визуальной студии вы можете проверить.

0 голосов
/ 10 марта 2011

Это плохая идея, потому что это пустая трата пространства.Вам нужно хранить только одно число, а не все.

Кроме того, вместо написания набора методов для этого можно реализовать оператор ==, который будет выглядеть более естественным для использования.

Кстати: ваша логика - ранг + масть - это критерий для сравнения?9-й ранг масти 4 лучше 10-го ранга масти 2?Я не уверен, что это за игра, которую вы имитируете, но обычно ранг предшествует мастям ... Но это зависит от реальных требований, конечно, просто сказать ....

Re yourвопросы по использованию методов -> и get - посмотрите на ошибки компилятора, когда они появятся.Да, в методах get вы возвращаете массив.Но если вы перестанете использовать массивы и сохраните только то, что вам нужно - методы будут хорошими.

Если вы хотите вернуть строку по какой-либо причине - вы можете сопоставить целочисленный индекс, который вы храните, с правильной строкой внекоторый статический массив, так что вы не будете хранить избыточные строки в разных экземплярах классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...