Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Выдать пять не повторяющихся карт

#cpp #разработка_игр #случайные_числа


Условие задачи.
Дана колода из 52 карт. Необходимо выдать 5 не повторяющихся карт. Масти и номиналы
хранить в двух разных массивах. Использовать класс string нельзя.

Что сделал я?

#include 
#include  // если старый компилятор, то заменить на "time.h"

// для отображения используемых в программе символов, измените шрифт консоли на "точечные
шрифты"

int main()
{
    srand(time(0)); // для генерации псевдорандомных чисел с привязкой к текущему времени

    // объявляем и инициализируем константы
    const short jack = 11;
    const short queen = 12;
    const short king = 13;
    const short ace = 14;

    // используем только нужные объекты
    using std::cout;
    using std::endl;
    using std::cin;

    // создаем два массива для хранения мастей и номиналов
    char *suit = new char[4]{ 3, 4, 5, 6 }; // 3 ... 6 - коды в ascii для символов мастей
    short *face = new short[13]; // номиналы

    // заполняем массив номиналов цифрами от 2 до 14, 
    // где 2 ... 10 - будут выводится как простые числа, 
    // а 11 ... 14 - как символы, в соотвествии с константами
    for (int i = 0; i < 13; i++)
        face[i] = i + 2;

    cout << " Your Deck : " << endl;

    // случайные индексы элементов, которые мы будем выводить
    short rand_index_suit;
    short rand_index_face;

    for (int i = 1; i <= 5; i++) // выдаем 5 карт
    {
        // генерируем псевдорандомные числа (тут, индексы) и заполняем ими переменные
        rand_index_suit = rand() % 4; // от 0 до 3
        rand_index_face = rand() % 13; // от 0 до 12

        cout << " " << i << ". "; // выводим номер карты

        // если элемент с рандомным индексом равен следующему числу, то выводим его
в соответствии с написанным ниже
        switch (face[rand_index_face]) 
        {
            case jack: { // валет
                cout << " J"; 
                break;
            }
            case queen: { // дама
                cout << " Q"; 
                break;
            }
            case king: { // король
                cout << " K";
                break;
            }
            case ace: { // туз
                cout << " A";
                break;
            }

            default: { // обычное число
                cout << " " << face[rand_index_face];
                break;
            }
        }

        // выводим масть с рандомным индексом
        cout << suit[rand_index_suit] << endl;
    }

    return 0; // если Visual Studio
}


Что не так с моей программой? Что нужно добавить?
В этом вся суть вопроса. Нужно выдать 5 не повторяющихся карт. А мое решение в худшем
случае может выдать такие 5 карт:
K♠ K♠ K♠ K♠ K♠
Здесь я подразумеваю то, что карты могут повторяться в выводе моей программы.
Есть ли варианты решения этой проблемы, придуманные мной?
Откровенно говоря, за ними я и обратился сюда :).
Но один есть:
Выбрать начальную позицию (сгенерировать начальный индекс) в массиве номиналов и
с каждым разом увеличивать его на один. Выход за границы массива предусмотрен.
5♠ 6♥ 7♥ 8♣ 9♠
Этот вариант не интересный и простой, как по мне.
Коротко о том, что не так и что нужно сделать
Мое решение может выдать 2 и больше одинаковых карт.
Примеры работы моей программы:
7♦ Q♠ A♣ 2♣ Q♠ - дважды повторилась карта Q♠;
2♦ 5♠ J♣ 2♦ 2♦ - трижды повторилась карта 2♦.
Нужно запретить программе делать такую ересь :).
Точнее говоря, нужно чтобы программа выдала 5 карт без повторов.
Напоминаю, использование класса string в решении этой задачи запрещено.  

Надеюсь, я понятно описал свой вопрос. Заранее благодарен за любую вашу помощь!
    


Ответы

Ответ 1



Вот. Только, простите уж, десятку выдает как 0 :) int main() { int cards[52]; for(int i = 0; i < 52; ++i) cards[i] = i; // Заполнение колоды for(int i = 0; i < 5; ++i) // Равномерное случайное перемешивание { // первых 5 карт с выводом int j = rand()%(52-i)+i; int t = cards[j]; cards[j] = cards[i]; cards[i] = t; cout << "A234567890JQK"[t%13] << "♦♠♥♣"[t/13] << endl; } }

Ответ 2



Нужно где-то запоминать уже использованные карты. #include #include // если старый компилятор, то заменить на "time.h" // для отображения используемых в программе символов, измените шрифт консоли на "точечные шрифты" int main() { srand(time(0)); // для генерации псевдорандомных чисел с привязкой к текущему времени // объявляем и инициализируем константы const short jack = 11; const short queen = 12; const short king = 13; const short ace = 14; // используем только нужные объекты using std::cout; using std::endl; using std::cin; // создаем два массива для хранения мастей и номиналов char *suit = new char[4]{ 3, 4, 5, 6 }; // 3 ... 6 - коды в ascii для символов мастей short *face = new short[13]; // номиналы // заполняем массив номиналов цифрами от 2 до 14, // где 2 ... 10 - будут выводится как простые числа, // а 11 ... 14 - как символы, в соотвествии с константами for (int i = 0; i < 13; i++) face[i] = i + 2; cout << " Your Deck : " << endl; // случайные индексы элементов, которые мы будем выводить short rand_index_suit; short rand_index_face; const short N=5; short deck_face[N]={}; short deck_suit[N]={}; for (int i = 0; i < N; i++) // выдаем 5 карт { bool used=true; // генерируем псевдорандомные числа (тут, индексы) и заполняем ими переменные while(used) { used = false; rand_index_suit = rand() % 4; // от 0 до 3 rand_index_face = rand() % 13; // от 0 до 12 for (int j = 0; j < i; j++) { if(deck_face[j]==face[rand_index_face] && deck_suit[j]==suit[rand_index_suit]) { used = true; break; } } if(!used) { deck_face[i] = face[rand_index_face]; deck_suit[i] = suit[rand_index_suit]; } } cout << " " << i+1 << ". "; // выводим номер карты // если элемент с рандомным индексом равен следующему числу, то выводим его в соответствии с написанным ниже switch (face[rand_index_face]) { case jack: { // валет cout << " J"; break; } case queen: { // дама cout << " Q"; break; } case king: { // король cout << " K"; break; } case ace: { // туз cout << " A"; break; } default: { // обычное число cout << " " << face[rand_index_face]; break; } } // выводим масть с рандомным индексом cout << suit[rand_index_suit] << endl; } return 0; // если Visual Studio } Как пример, вместо 5 карт сгенерируем все 52 карты в случайном порядке. (изменил только N). (не могу добавить комментарий так как <50 реп. Напишу тут) @Harry у Вас, некорректно работает код. Как уже сделали в замечание, иногда могут попасться повторяющиеся карты.

Ответ 3



Если количество выбираемых карт настолько сильно меньше размера множества, из которого делается выбор (5 из 52), то эффективнее всего применить "студенческий" алгоритм с запоминанием выбранных карт и повторным выбором #include #include int main(int argc, const char * argv[]) { const char *const SUITS = "\x3\x4\x5\x6"; const char *const FACES[] = { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" }; unsigned char flags[4][13] = {}; for (unsigned n = 5; n > 0; --n) { unsigned suit, face; do suit = std::rand() % 4, face = std::rand() % 13; while (flags[suit][face]); flags[suit][face] = true; std::cout << SUITS[suit] << FACES[face] << std::endl; } } Для задач, в которых количество выбираемых карт сравнимо с размером множества, такой алгоритм подходил бы плохо.

Комментариев нет:

Отправить комментарий