Я пытаюсь сделать простую программу для блэкджека. К сожалению, у меня сразу возникли проблемы с созданием колоды карт.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<char> deck;
char suit[] = {'h','d','c','s'};
char card[] = {'2','3','4','5','6','7','8','9','10','J','Q','K','A'};
for (int j=0; j<13; j++) {
for (int i=0; i<4; i++) {
deck.push_back(card[j] suit[i]);
}
}
return 0;
}
Я знаю, что моя проблема начинается с того, что я пытаюсь присвоить символу значение «10». Очевидно, я не смог заставить это скомпилировать, но я уверен, что когда я попытаюсь присвоить значения карт векторной колоде, я также получу ошибку, так как я использовал тип переменной 'char'. Мне кажется, что знание того, какой тип переменной использовать, убивает. Кроме того, будет 'deck.push_back (card [j] suit [i]); » быть правильным кодом для объединения карты и масти, или вам нужно поставить что-то между картой [j] и мастью [i]? Я был бы признателен, если бы кто-нибудь из вас мог вести меня в правильном направлении. Также в качестве небольшого примечания, это часть домашнего задания, поэтому, пожалуйста, не давайте мне просто целые блоки кода. Спасибо за вашу помощь.
Итак ... чем ты закончил?





Используйте букву «Т» вместо 10.
Вы пробовали заменить J на 11, Q на 12 и K на 13? Тогда вы могли бы использовать integers вместо characters. Позже замените 11-13 соответствующей буквой.
Вы можете использовать uint8_t из stdint.h в качестве целочисленного типа, и ваша структура будет такого же размера, как если бы вы использовали char.
Попробуйте создать класс Card с мастью и картой в качестве члена и установить его как тип вектора. Нравиться
public class Card {
public:
Card(char suit, char card);
char suit, card;
};
int main() {
vector<Card> deck;
char suit[] = {'h','d','c','s'};
char card[] = {'2','3','4','5','6','7','8','9','T','J','Q','K','A'};
for (int j=0; j<13; j++) {
for (int i=0; i<4; i++) {
deck.push_back(new Card(card[j],suit[i]));
}
}
return 0;
}
также использование перечислений вместо символов в масти и карте сделало бы его более понятным.
Я думаю, у вас все еще будет проблема с «10» в массиве символов.
Подумайте о перечислениях для масти и ранга.
Используйте sizeof (карта) и sizeof (масть) вместо магических чисел 13 и 4.
Если вы используете Enums для лица и масти, как вы заполняете колоду? Вы не можете перебирать перечисления и не можете искать перечисления по их значениям, насколько мне известно?
это должна быть векторная колода <Card *>; если вы нажмете новую Карту в векторе.
Как упоминалось другими, вы можете использовать «T» для десяти, J, Q и K для цифр. Что касается push_back .. поскольку колода - это вектор символов, вы можете передать только один символ в push_back в качестве аргумента. Передача значения карты (1 ... 9, T, J, Q, K) и его набора не работает.
Я лично создал бы небольшую структуру для представления карты со свойством Value и Suite. Затем вы можете сделать свою колоду вектором карт.
Отредактировано: исправлено последнее слово, так как вектор (меньше) Карточка (больше) визуализировалась как вектор (ничего).
Ну, во-первых, deck [0] - это один символ, но вы пытаетесь вставить в него «2h». (на данный момент мы проигнорируем то, как вы это делаете, неправильно.)
По сути, вам нужно сделать деку vector<std::string>. Сделайте card массивом const char * s и преобразуйте элементы в строку.
затем используйте:
deck.push_back(std::string(card[j]) + suit[i]);
Я думаю, что это хороший подход - использовать строки вместо символов.
Я думаю, что вы хотите использовать перечисление. Это сделает ваш код более понятным и решит вашу проблему.
enum SUIT { HEART, CLUB, DIAMOND, SPADE };
enum VALUE { ONE, TWO, THREE, ..., TEN, JACK, QUEEN, KING};
Поскольку это программа для игры в блэкджек, вы будете складывать и сравнивать значения карт.
В этом случае вы можете сэкономить дополнительное программирование и избавиться от лишних хлопот, задав для карт значения int (1-13) вместо значений символ.
За исключением того, что в блэкджеке несколько разных карт имеют одинаковое естественное значение, а одна карта имеет два значения.
Верно, но у вас будет та же проблема с символами, и вы можете упростить условия для проверки следующим образом: 1: значение по умолчанию 1 (Ace) равно 11, если ваша сумма уже не превышает 21, и в этом случае это 1 . 2: Если значение карты больше 10, сделайте его равным 10, иначе используйте его собственное значение.
Я бы согласился с предложением Росса использовать целые числа. В большинстве карточных игр требуется немного математики, так что это лучшее представление.
На выходе преобразовать в «A» или «ACE» и т. д.
То, как вы это моделируете, действительно зависит от того, что вы пытаетесь сделать.
Вы создаете настоящую игру, а структуры данных должны поддерживать игровой процесс?
Если это так, я бы создал класс карты с полем перечисления для масти и числовым типом (со значениями от 1 до 13) для номинала.
С другой стороны, если вы создаете приложение для анализа или ИИ-плеер, модель может немного отличаться.
Несколько лет назад я написал симулятор для расчета вероятностей в различных сценариях Техасского Холдема, и мне хотелось, чтобы он ДЕЙСТВИТЕЛЬНО быстро вычислял числа. Я начал с очень простой модели (класс карты, перечисление мастей и т. д.), Но после долгого профилирования и оптимизации я получил побитовое представление.
Каждая карта представляла собой шестнадцатибитовое значение, причем тринадцать старших битов представляли номинальную стоимость, два младших бита представляли масть, а бит [2] был специальным флагом, указывающим туз (использовался только в тех случаях, когда в стрите A2345 может появиться туз).
Вот несколько примеров:
0000000000001001 <---- Two of hearts
0100000000000011 <---- King of spades
1000000000000110 <---- Ace of diamonds
^^^^^^^^^^^^^ ("face-value" bits)
^ ("low-ace" flag)
^^ ("suit" bits)
Вы можете себе представить, как с таким дизайном очень быстро искать пары, тройки и стриты (флеши немного сложнее).
Я не буду вдаваться во все конкретные операции, но достаточно сказать, что такая модель поддерживает миллионы операций в секунду ...
Конечно, имейте в виду, я на самом деле не защищаю, чтобы вы использовали подобный дизайн в простой реализации игры. Единственная причина, по которой я остановился на этом дизайне, заключается в том, что мне нужно было провести масштабное статистическое моделирование.
Так что хорошенько подумайте, как вы хотите моделировать:
Общая модель приложения и цели приложения в целом в значительной степени будут определять типы структур данных, которые будут наиболее подходящими.
Веселиться!!!
Поскольку это домашнее задание для C++, я предполагаю, что вы должны использовать классы. В противном случае используйте перечисления, а если это был C, используйте структуру или что-то в этом роде.
А для некоторых игр, помимо количества очков, вам нужно сохранить какой-то ранг для карты, который будет зависеть от текущего режима игры.
Я никогда не писал простой C, но я имею в виду что-то вроде этого:
typedef struct struct_card {
unsigned short int suit:2;
unsigned short int card:4;
// unsigned short int valu:4;
} card;
int main() {
card a_card;
card std_deck[52];
const unsigned short int rummy_value[13] = {1,2,3,4,5,6,7,8,9,10,10,10,10};
const char *std_card_name[13] = {"Ace","Two","Three","Four","Five","Six",
"Seven","Eight","Nine","Ten","Jack","Queen","King"};
const char *std_suit_name[4] = {"Spades","Clubs","Hearts","Diamonds"};
int j, k, i=0;
for(j=0; j<4; j++){
for(k=0; k<13; k++){
a_card.suit=j; a_card.card=k;
std_deck[i++] = a_card;
}
}
//check our work
printf("In a game of rummy:\n");
for(i=0;i<52;i++){
printf(" %-5s of %-8s is worth %2d points.\n",
std_card_name[std_deck[i].card],
std_suit_name[std_deck[i].suit],
rummy_value[std_deck[i].card]);
}
//a different kind of game.
enum round_mode {SHEILD_TRUMP, FLOWER_TRUMP, BELL_TRUMP, ACORN_TRUMP, BOCK, GEISS} mode;
const card jass_deck[36] = {
{0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},
{1,1},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},
{2,2},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},
{3,3},{3,1},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{3,8},
};
#define JASS_V {11,0,0,0,0,10,2,3,4}
const unsigned short int jass_value[9] = JASS_V;
#define JASS_TRUMP_V {11,0,0,0,14,10,20,3,4}
const unsigned short int jass_trump_value[9] = JASS_TRUMP_V;
#define JASS_BOCK_V {11,0,0,8,0,10,2,3,4}
const unsigned short int jass_bock_value[9] = JASS_BOCK_V;
#define JASS_GEISS_V {0,11,0,8,0,10,2,3,4}
const unsigned short int jass_geiss_value[9] = JASS_GEISS_V;
const char *jass_card_name[9] = {"Ace","Six","Seven","Eight","Nine","Banner",
"Under","Ober","King"};
const char *jass_suit_name[4] = {"Sheilds","Flowers","Bells","Acorns"};
const unsigned short int jass_all_value[6][4][9] = {
{ JASS_TRUMP_V, JASS_V, JASS_V, JASS_V },
{ JASS_V, JASS_TRUMP_V, JASS_V, JASS_V },
{ JASS_V, JASS_V, JASS_TRUMP_V, JASS_V },
{ JASS_V, JASS_V, JASS_V, JASS_TRUMP_V },
{ JASS_BOCK_V, JASS_BOCK_V, JASS_BOCK_V, JASS_BOCK_V },
{ JASS_GEISS_V, JASS_GEISS_V, JASS_GEISS_V, JASS_GEISS_V }
};
//check our work 2: work goes on summer vacation
printf("In a game of jass with trump (Sheilds | Flowers | Bells | Acorns) | Bock | Geiss\n");
for(i=0;i<36;i++){
printf(" %-6s of %-7s is worth %8d%10d%8d%9d%8d%8d\n",
jass_card_name[jass_deck[i].card],
jass_suit_name[jass_deck[i].suit],
jass_all_value[SHEILD_TRUMP][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[FLOWER_TRUMP][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[BELL_TRUMP][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[ACORN_TRUMP][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[BOCK][jass_deck[i].suit][jass_deck[i].card],
jass_all_value[GEISS][jass_deck[i].suit][jass_deck[i].card]);
}
return 0;
}
Результат выглядит так:
In a game of rummy:
Ace of Spades is worth 1 points.
Two of Spades is worth 2 points.
Three of Spades is worth 3 points.
Four of Spades is worth 4 points.
Five of Spades is worth 5 points.
...
Nine of Diamonds is worth 9 points.
Ten of Diamonds is worth 10 points.
Jack of Diamonds is worth 10 points.
Queen of Diamonds is worth 10 points.
King of Diamonds is worth 10 points.
In a game of jass with trump (Sheilds | Flowers | Bells | Acorns) | Bock | Geiss
Ace of Sheilds is worth 11 11 11 11 11 0
Six of Sheilds is worth 0 0 0 0 0 11
Seven of Sheilds is worth 0 0 0 0 0 0
Eight of Sheilds is worth 0 0 0 0 8 8
Nine of Sheilds is worth 14 0 0 0 0 0
Banner of Sheilds is worth 10 10 10 10 10 10
...
Under of Acorns is worth 2 2 2 20 2 2
Ober of Acorns is worth 3 3 3 3 3 3
King of Acorns is worth 4 4 4 4 4 4
Блэкджек - это скучно. Этот код компилируется.
Возможно, это не компилируется, но вот подход, который я бы (и использовал). Вы захотите использовать целые числа для представления своих карточек, но вы можете легко абстрагироваться от этого в классе. Который я вам напишу.
class Card
{
public:
enum ESuit
{
kSuit_Heart,
kSuit_Club,
kSuit_Diamond,
kSuit_Spade,
kSuit_Count
};
enum ERank
{
kRank_Ace,
kRank_Two,
kRank_Three,
kRank_Four,
kRank_Five,
kRank_Six,
kRank_Seven,
kRank_Eight,
kRank_Nine,
kRank_Ten,
kRank_Jack,
kRank_Queen,
kRank_King,
kRank_Count
};
static int const skNumCards = kSuit_Count * kRank_Count;
Card( int cardIndex )
: mSuit( static_cast<ESuit>( cardIndex / kRank_Count ) )
, mRank( static_cast<ERank>( cardIndex % kRank_Count ) )
{}
ESuit GetSuit() const { return mSuit );
ERank GetRank() const { return mRank );
private:
ESuit mSuit;
ERank mRank;
}
Теперь его очень просто добавить к этому классу, чтобы получить от него все, что вы хотите. Создать список так же просто, как показано ниже.
rstl::vector<Card> mCards;
mCards.reserve( Card::skNumCards );
for ( int cardValue = 0; cardValue < Card::skNumCards; ++cardValue )
{
mCards.push_back( Card( cardValue ) );
}
Вам нужно перетасовать?
#include <algorithm>
std::random_shuffle( mCards.begin(), mCards.end() );
Как насчет того, чтобы посмотреть, какова ценность первой карты?
if ( mCards[0].GetSuit() == Card::kRank_Club && mCards[0].GetRank() == Card::kRank_Ace )
{
std::cout << "ACE OF CLUBS!" << std::endl;
}
Я не компилировал ничего из этого, но это должно быть близко.
Когда я создал мой класс колоды карт C++, я столкнулся с несколькими собственными проблемами. Во-первых, я пытался преобразовать мой класс колоды карт PHP в C++ с минимальной удачей. Я решил сесть и просто изложил это на бумаге. Я решил использовать объектно-ориентированную установку, в основном потому, что считаю ее наиболее простой в использовании для расширения. Я использую объекты Открытка и Палуба, поэтому, например, если вы хотите поместить 10 колод в Обувь вашей игры в блэкджек, вы можете создать 10 колод, что было бы достаточно просто, потому что я решил сделать все самодостаточным. Фактически, он настолько самодостаточен, что для создания вашей обуви код будет следующим:
#include "AnubisCards.cpp"
int main() {
Deck *shoe = new Deck(10);
}
Но это было для простоты, не совсем то, что нужно в небольших играх, где вам нужна только одна колода.
В любом случае, я сгенерировал колоду, создав массив из 52 объектов Card. Колоды достаточно просты, потому что вы знаете, что у вас есть 4 костюма и 13 карт в каждой масти, вы также знаете, что у вас есть 2,3,4,5,6,7,8,9,10, валет, дама, король, туз в каждой масти. Это никогда не изменится. Поэтому я использовал две петли, одну для Подходить, а другую для Ценить.
Это было примерно так:
for(int suit = 1; suit <= 4; suit++){
for(int card = 1; card <= 13; card++){
// Add card to array
}
}
Теперь вы заметите, что в каждом из этих циклов я использую целочисленное значение. Причина проста, карты - это числа. 4 костюма. 13 значений. Даже числовое значение в игре Блэкджек. Номинальное значение, пока вы не нажмете лицевые карты, которые имеют числовое значение 10, пока вы не нажмете туз, который имеет числовое значение 1 или 11. Все - числа. Таким образом, вы можете использовать эти числа не только для определения значения карты, но и для определения масти карты и числа в числовой последовательности.
Одна из идей - хранить карту в классе Card с символьными или строковыми именами карт, где 1,2,3 ... являются индексами для каждой.
И ваш профессор подумает, что вы блестяще справитесь с домашним заданием на этой неделе :)