Подсчет нулевых значений в массиве - PullRequest
2 голосов
/ 21 сентября 2010

Создание игры uno для проекта.

все 108 карт расположены в заполненном массиве с именем cardDeck [108]

функция запуска вытягивает 7 карт случайным образом и заполняет руку игрокадобавив их в массив playerHand []

Мне нужна помощь в этом, пожалуйста.

1) Я не знаю, как заставить карты исчезать из массива cardDeck, когда онивытащил в playerHand [].

2) Я также не знаю, как создать что-то, что будет считать ненулевые значения в массиве cardDeck, чтобы он отображал общее количество карт, оставшихся в колоде послеоба игрока берут карты.

Ответы [ 7 ]

12 голосов
/ 21 сентября 2010
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;

Сделать колоду vector.

vector<Card> deck_;

Вставить каждую карту в колоду.

deck_.push_back(Yellow0);
deck_.push_back(WildDraw4);

Перетасовать колоду

srand((unsigned)time(0));
random_shuffle(deck_.begin(), deck_.end());

Возьмите карты из колоды и положите их в руку игрока.

vector<Card> player_hand_;
for( size_t i = 0; i < 7; ++i )
{
  player_hand_.push_back(deck_[0]);
  deck_.erase(deck_.begin());
}

РЕДАКТИРОВАТЬ:

За запрос в комментариях ниже, я будуобъясните, почему я считаю, что должно быть несколько векторов карт без сохранения состояния, а не один вектор карт с сохранением состояния.

Один из идеалов, к которым ООП пытается приблизиться, - это моделирование реального мира как можно ближе.Теперь, очевидно, vector не является ООП, но карты, содержащиеся в нем, теоретически могут быть.И хотя во многих случаях это, конечно, не может быть достигнуто идеально, или даже должно быть предпринято попытка достичь идеального результата во многих случаях, попытка смоделировать программные компоненты после того, как IMO реального мира превзойдет любую конкретную парадигму программирования.Итак, рассмотрим карты Уно.У карты Uno есть несколько разных свойств.Они имеют ранг (0-9) и костюм (красный, синий, желтый, зеленый).Есть также несколько карт, которые имеют особое значение и не имеют ни масти, ни ранга (WildDraw4, Wild, Draw2, Skip, reverse).

Так что, если бы мы смоделировали карту Uno в C ++, как бы она выглядела?лайк?Карты Uno не меняются после печати.Например, желтая 2 никогда не будет зеленой 5 или дикой ничьей 4.Если вы достанете green7 из коробки и передадите его другу, это все равно green7.Теперь он в руках вашего друга, но это не то, что изменилось в отношении карты .Скорее всего, изменилась рука твоего друга.Вместо того, чтобы быть пустым, теперь он держит зеленую карту Uno.

В игре Uno каждому игроку раздается по 7 карт.Есть одна карта, лежащая лицом вверх, которая становится колодой сброса, а остальные карты кладутся лицом вниз, образуя колоду сброса.Когда вы перемещаете карту из колоды розыгрыша в руку игрока, карта все равно не изменилась, хотя ее местоположение изменилось.Но не зацикливайтесь на человеческом языке.«Это местоположение» не означает, что местоположение карты является собственностью карты.Но когда вы перемещаете карту, что-то изменилось - состояния колоды розыгрыша и руки игрока.

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

Этот дизайн легко понять программисту, легко расширить и легко разработать в первый раз.Поскольку это просто, это также не особенно склонно к дефектам.В конце концов, что может сломаться - скейтборд или космический челнок?

2 голосов
/ 21 сентября 2010

Просто используйте std::vector<card>. Это динамически изменяемый контейнер, из которого вы можете удалять элементы.

1 голос
/ 21 сентября 2010

Полагаю, вы используете какой-то нестандартный тип для карточек.Итак, давайте назовем это t_card_kind.

Вы можете сделать какое-то изменение массива, чтобы «удалить» карту из руки игрока.Но это не имеет особого смысла.

Я бы посоветовал определить перечисление как

namespace uno { enum play_status { DRAW_PILE,IN_HAND,DISCARD }; };

Таким образом, вы можете просто объявить новую структуру с определенным типом

typedef struct s {
   t_card_kind card;
   uno::play_status status;
} t_game_card;

... и, наконец, объявите массив, такой как

t_game_card my_cards[108];

, или вектор, такой как: vector my_cards [108];

, а затем заполните его.

Чтобы изменить статус карты, просто войдите в нее.

Например,

my_cards[i].status = uno::IN_HAND;

Этот дизайн будет выполняться намного быстрее и более элегантно.

Чтобы решить ваш второй вопроспросто реализуйте метод, подобный

unsigned int count_status(const t_game_card * my_card, 
                          uno::play_status status_kind) {
   const unsigned int DECK_SIZE = 108; //size of a standard uno deck
   unsigned int matches;
   for (unsigned int counter=0; counter < DECK_SIZE;counter++) {
      if (t_game_card[counter].play_status==status_kind) {
         matches++;
      }
   }
   return matches;
}

... Или просто переключитесь на векторы и используйте метод erase ().


EDIT 1
Основываясь на моем предыдущем обсуждении с Джоном, ведутся споры о дизайне одного контейнера в сравнении с дизайном нескольких контейнеров.Вот мое мнение по теме:

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

В вашем результирующем коде у вас будет что-то вроде:

namespace uno { enum play_status { DRAW_PILE,IN_HAND,DISCARD }; };    
typedef struct s { t_card_kind card; uno::play_status status; } t_game_card;    
static vector<t_game_card> my_cards[108];

Где многовекторный подход будет иметь:

static t_game_card draw_pile[108];
static t_game_card in_hand;
static t_game_card discards;

... еще три элемента, хотя мой немного длиннее линии.

Как уже говорилось ранее, чтобы изменить состояние с помощью моего подхода, вы просто использовали бы что-то вроде:

my_cards[i]=uno::IN_HAND;

, тогда как свекторный метод, вам нужно сделать что-то вроде:

in_hand.append(draw_pile[i]);
draw_pile.erase(draw_pile.begin()+i);

Это длиннее , больше вычислительно интенсивно , использует больше памяти и, на мой взгляд, менее интуитивно .

Теперь давайте рассмотрим расширяемость .Допустим, вы придумали вариант uno, который включает в себя кучу «БОНУС».С моим подходом это просто - просто добавьте значение к перечислению:

namespace uno { enum play_status { DRAW_PILE,IN_HAND,DISCARD,BONUS }; };

с векторным подходом, вам нужно будет создать и поддерживать целый дополнительный вектор:

    static t_game_card draw_pile[108];
    static t_game_card in_hand;
    static t_game_card discards;
    static t_game_card bonus;

Теперь у нас есть 4 (!) Переменных с векторным подходом по сравнению с одной интуитивно понятной переменной с моим подходом.

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

1 голос
/ 21 сентября 2010

Рассмотрим эту альтернативную реализацию и логику.

  • Определите CardCollection как класс, который "имеет"

    std::deque<boost::shared_ptr<Card> >

  • Определите три CardCollection s - одна колода, две другие - руки игрока

  • Инициализируйте колоду с помощью push_back всех Card объектов.(в случайном порядке) на deque.

  • вытянуть Card s из колоды с помощью pop_front () на его deque

  • переместите их в соответствующую
    руку игрока на push_back к этому
    deque, сотрите в колоде deque
    (решает 1)

  • 2) решается вызовом size() на колоде deque

  • , когда рука заканчивается, верните Card s в колоду, используя push_back()

1 голос
/ 21 сентября 2010

Оставьте целое число (назовем его N), обозначающее количество карт, оставшихся в колоде. Чтобы удалить карту из колоды, выберите случайное число r от 0 до N (т. Е. 0 <= r <N), поменяйте местами последнюю карту в массиве, уменьшите N и верните карту, которую вы только что обменяли до конца массива. </p>

Таким образом, вы никогда не вводите NULL в массив, поэтому полностью избегаете вашей проблемы. Если вы используете вектор stl вместо массива, это становится еще проще, поскольку вектор знает его размер без необходимости хранить его самостоятельно.

1 голос
/ 21 сентября 2010

Вы можете присвоить вытянутым картам значение / символ, которого нет ни у одной карты.Таким образом, сообщая вам, какие карты были разыграны ...

0 голосов
/ 21 сентября 2010

Я бы порекомендовал что-то вроде этого (это немного сложнее, но должно работать):

Add all cards to a deque (push back)

(optionally) Shuffle (randomly sort) the collection

Loop 7 times
{
    For each player
    {
       Removing the first card from the collection and add it to the player's hand
    }
}

Вы должны получить руки из 7 карт, и все, что осталось в колоде, очень легко сосчитать.или работать с (все осталось в деке).

Теперь я бы рекомендовал использовать векторы для рук игрока вместо массивов, хотя разница здесь довольно небольшая, поскольку у вас есть известное количество элементов.С векторами легче работать.Если вы еще этого не сделали, я бы также создал класс Card и оставил бы колоду и руки как deque<Card*> и vector<Card*>, что сделает движущиеся карты быстрыми (скопируйте указатель, который является одной из инструкций) иПерестановка будет довольно быстрой для небольших типов данных.

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