[解決済み] C++でカードのデッキを生成するのを手伝ってほしい
質問
C++を使用して、カードのデッキを生成しようとしています。すでにすべてのコードを書きましたが、どうしても解けない問題があります。
Deck::Deck(){
Card card;
bool match = false;
for (int i=0;i<47;i++){
do{
card.setCard();
match = cardInDeck(card, i);
}while(match == true);
match = false;
cards[i] = card;
}
numDrawn = 0;
}
Deckクラスのコンストラクタでは、52枚のカードをすべて生成して、デッキに一致するカードがないことを確認するfor()ループを用意しています。少なくとも、そうする必要があります。しかし、このループを47回以上繰り返しても、うまくいかないのです。47回を超えると、実行時にコンソール画面が空っぽになり、カーソルが点滅する以外には何も表示されません。47を超える数値の何が原因で動作しなくなるのか、よくわかりません。広範囲にテストした結果、0から48の間のすべての数字が動作しました。
もしかしたら、私のコードのどこかに、私が見ていないだけで、小さなエラーがあるのかもしれません。本当にわかりません。しかし、私は本当に私が得ることができる任意の助けを感謝します。
以下は私の全コードです。
#include<iostream>
#include<stdlib.h>
using namespace std;
void run();
class Card{
private:
char suit;
int value;
public:
Card();
void setCard();
void getCard();
int getValue();
int getSuit();
};
class Deck{
private:
Card cards[52];
int numDrawn;
public:
Deck();
void shuffle();
void draw();
bool cardInDeck(Card card, int index);
};
int main(){
run();
}
Card::Card(){
srand(time(NULL));
value = rand() % 12 + 1;
suit = rand() % 4 + 1;
}
void Card::setCard(){
value = rand() % 12 + 1;
suit = rand() % 4 + 1;
}
void Card::getCard(){
cout<<" ----"<<endl<<"| |"<<endl<<"| ";
if (value == 1) cout<<'A';
else if (value == 10) cout<<'J';
else if (value == 11) cout<<'Q';
else if (value == 12) cout<<'K';
else cout<<value;
if (suit == 1) cout<<(char)3;
else if (suit == 2) cout<<(char)4;
else if (suit == 3) cout<<(char)5;
else cout<<(char)6;
cout<<" |"<<endl<<"| |"<<endl<<" ----"<<endl;
}
int Card::getSuit(){
return suit;
}
int Card::getValue(){
return value;
}
bool Deck::cardInDeck(Card card, int index){
bool match;
for(int i=0;i<=index;i++){
if((card.getValue() == cards[i].getValue()) && (card.getSuit() == cards[i].getSuit())){
match = true;
break;
}
else match = false;
}
return match;
}
Deck::Deck(){
Card card;
bool match = false;
for (int i=0;i<47;i++){
do{
card.setCard();
match = cardInDeck(card, i);
}while(match == true);
match = false;
cards[i] = card;
}
numDrawn = 0;
}
void Deck::shuffle(){
Card card;
bool match = false;
for (int i=0;i<52;i++){
do{
card.setCard();
match = cardInDeck(card, i);
}while(match == true);
match = false;
cards[i] = card;
}
numDrawn = 0;
}
void Deck::draw(){
cards[numDrawn].getCard();
numDrawn++;
}
void run(){
Deck cards;
char choice;
int cardsDrawn = 0;
cout<<"Enter 's' to shuffle the deck, 'd' to draw a card, or 'x' to exit: ";
do{
cin>>choice;
switch(choice){
case 'X':
case 'x':break;
case 'S':
case 's':cards.shuffle();
cout<<"Deck shuffled."<<endl;
cardsDrawn = 0;
break;
case 'D':
case 'd':if (cardsDrawn == 52){
cout<<"Out of cards. Deck reshuffled."<<endl;
cards.shuffle();
cardsDrawn = 0;
break;
}
else{
cards.draw();
cardsDrawn++;
break;
}
default: cout<<"Invalid entry.\a Enter a valid option('s','d','x'): ";
}
}while((choice != 'x') && (choice != 'X'));
}
解決方法は?
13個あります。 値 52枚のカードで
Card::Card(){
srand(time(NULL));
value = rand() % 13 + 1;
suit = rand() % 4 + 1;
}
void Card::setCard(){
value = rand() % 13 + 1;
suit = rand() % 4 + 1;
}
12 * 4
->
48
13 * 4
->
52
12の値を持つ元のコードでは48種類のカードしか生成できないので、52を生成しようとすると無限ループになるのはこのためです。
編集中です。
ちなみに、フォローすべきは エリックの とHans Passant(質問に対するコメント参照)のアドバイスがあります。シャッフルのやり方は いけない もっとシンプルで自然でクリーンな方法があるという意味で。以下をご覧ください。
/**
* Forward counting implementation of Fisher-Yates / Knuth shuffle.
* see https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
*/
template< typename A >
void shuffle ( A& a, int i, const int j ) {
// one item left => no need to shuffle
const int _j = j - 1;
for ( ; i < _j ; ++i ) {
// pick item uniformly at random to put at ith position
// once moved the item will stay in place
const int k = i + rand() % ( j - i );
// swap
auto tmp = a[i];
a[i] = a[k];
a[k] = tmp;
}
}
の場合、52種類のカードをすべて一度に生成する必要があります。
Card::Card( const int value, const int suit ) {
this->value = value;
this->suit = suit;
}
// we do not need this anymore
// void Card::setCard(){
// value = rand() % 13 + 1;
// suit = rand() % 4 + 1;
// }
Card cards[52];
int i = 0;
for ( int suit = 1 ; suit <= 4 ; ++suit ) {
for ( int value = 1 ; value <= 13 ; ++value ) {
cards[i] = Card( value, suit );
++i;
}
}
そして最後にデッキをシャッフルします
shuffle( cards, 0, 52 );
この一般的な問題についての詳細な参考文献 : http://bost.ocks.org/mike/shuffle と http://blog.codinghorror.com/the-danger-of-naivete .
また、(drescherjmのコメントで提案されているように)srandの呼び出しをこのクラスの外に置くことを検討してください。srand の呼び出しは rand 関数の種をリセットするもので、基本的には main 関数の冒頭で一度だけ呼び出されるべきものです。あなたの場合、カードごとに setCard() を呼び出さないと、同じカードが 52 回も生成されてしまうかもしれません。 ランダム ( 参照 http://en.wikipedia.org/wiki/Pseudorandomness ).
時間があれば C++ランダム標準ライブラリヘッダ C の rand lib をはるかに上回る機能を提供します。にはシャッフルメソッドもあります。 <algorithm> !
関連
-
[解決済み] エラーが発生する。ISO C++は型を持たない宣言を禁じています。
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み】Visual C++で "Debug Assertion failed "の原因となる行を見つける。
-
[解決済み] 式はクラス型を持つ必要があります。
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み] C++で仮想関数が必要な理由とは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み】Cygwin Make bash コマンドが見つかりません。
-
[解決済み】'cout'は型名ではない
-
[解決済み】CMakeエラー at CMakeLists.txt:30 (project)。CMAKE_C_COMPILER が見つかりませんでした。
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み】標準ライブラリにstd::endlに相当するタブはあるか?
-
[解決済み] 数値定数の前にunqualified-idを付けて、数値を定義することを期待する。
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー