===== 9月6日 3時間目 関数の引数に渡した変数の値を変更したい話===== ==== C++の改行ってめんどいよねって話 ==== C++の標準出力で改行をしようとすると、通常は#include しておいて、std::coutでなんか表示して、std::endlで改行コードを送り込んで改行する。っていう感じになります。\\ 結構、煩わしいです。 #includ std::cout << "なんちゃらかんちゃら" << std::endl; \\ using namespace std;\\ を宣言すると、stdは省略できます。\\ でも、いろんなところで名前の衝突を起こしたりする恐れがあるため最近あまりお勧めされていません。\\ 代替策はいろいろありますが、その場で使うものだけを省略するようにusing宣言するってのが、マイブームかもしれません。 #include using std::cout; using std::cin; using std::endl; int a; cin >> a; cout << "a=" << a << endl; こんな感じ、かえって煩わしいという話もあるけど、危険回避はできそう。\\ また、それでも改行自体の書き方が煩わしいって話もあります。\\ みんなC言語のprintf関数が好きなんでしょうね。。。\\ そんな時は、改行のところだけCの関数puts(文字列)を~文字列で呼ぶといいかもしれないといううわさを聞いたことがあります。\\ puts("");\\ これで、何も表示せず改行します。\\ また、改行文字 '\n' をcoutで送り込むって作戦もあります。\\ cout << '\n';\\ あんまり、いい解決策じゃないか。。。\\ cout << "いえーい"; //\n 日本語だと¥nになることが多い。改行文字 cout << "\n"; puts(""); cout << "うえーい"; \\ ==== cinで読み込んだ値の大きさの配列を用意するはなし ==== 通常の配列は大きさがわかっていないと、宣言した時にどのぐらいの大きさのメモリを取っておいたらいいかシステムが判断しかねるので、あとから配列の大きさを変えたり、プログラムが動き出してからcinで読み込んだ値を使って通常の配列の宣言をするということはできません。\\ //こういう配列の取り方はできない。 #include using std::cout; using std::endl; using std::cin; int main() { int num; cin >> num; int arr[num]; for(int i=0;i これを実現するには、とっても前に学んだ動的配列を使います(stlってのもあるけど、それはまた後日)\\ #include using std::cout; using std::endl; using std::cin; int main() { int num; cin >> num; //配列の先頭アドレスを保存しておく入れ物を用意 int *arr = nullptr; //配列を取得して、その先頭アドレスをarrに代入 //これで、 arr ~ arr + num までが連続した領域として取得できる=arr[0] ~ arr[num-1]までが配列として使える。 arr = new int[num]; for(int i=0;i ==== 関数の引数に配列を渡す話 ==== どこかで何度も話したように、C++では、特殊な場合を除き配列全体を関数に渡すということはできません。\\ もしできたとしても、関数は基本的に引数で渡された変数のコピーを作成し、そのコピーの値を使ってさぎょうをするので、配列のようなでかいデータを渡して毎回毎回呼ぶたびにコピーされたらゲームなんて動いたもんじゃなくなります。\\ 配列を関数の引数で渡して、関数の内部で渡した配列の値を弄り回したいときは、アドレス渡し(ポインタ渡し)を使います。\\ #include using std::cout; using std::endl; using std::cin; //関数に配列のアドレス=0番のアドレスを渡す //先頭アドレス+個数 void printArray(int *pa, int n) { for(int i=0; i < n; i++) { cout << pa[i] << " "; //cout << *(pa + i) << " "; } } void initArray(int *pa, int n) { for(int i=0; i < n; i++) { pa[i] = i + 1; } } int main() { //動的配列の取得 int num; //データの個数 cin >> num; int *arr = new int[num]; //arr[0]~arr[num] initArray(arr, num); printArray(arr, num); } ==== 関数の引数に渡した変数の値を変更したい欲 ==== 通常、変数に引数を渡すと(仮引数に、実引数を渡すと)、関数内では実引数のコピーが作成されそのコピーに対して処理が行われます。 #include using std::cout; using std::endl; using std::cin; //こんなことをしても実引数の値は変えられないよ! ! void calc_sdm(int x, int y, int _sum, int _diff, int _mul) { _sum = x + y; _diff = x - y; _mul = x * y; } int main() { int a, b; //データの個数 cin >> a >> b; //sum : a+b //diff: a-b //mul : a*b int sum, diff, mul; cout << a << ", " << b << endl; //よーし!sum,diff,mulを計算だ! calc_sdm(a, b, sum, diff, mul); cout << "sum=" << sum << endl; cout << "diff=" << diff << endl; cout << "mul=" << mul << endl; //あれ。。。 } \\ なので、上のソースコードのような書き方をしても、実引数で与えた変数の値を変更することは”通常は”できません。\\ それをやるには、やっぱりアドレス渡し(ポインタ渡し)を行います。\\ #include using std::cout; using std::endl; using std::cin; //関数は、複数の引数(パラメタ)を受け取り、処理結果を一つの値で返す //関数の中で、渡した引数の値を変更したいときは、必ずアドレスで渡す void calc_sdm(int x, int y, int *_sum, int *_diff, int *_mul) { *_sum = x + y; *_diff = x - y; *_mul = x * y; } int main() { int a, b; //データの個数 cin >> a >> b; //sum : a+b //diff: a-b //mul : a*b int sum, diff, mul; cout << a << ", " << b << endl; calc_sdm(a, b, &sum, &diff, &mul); cout << "sum=" << sum << endl; cout << "diff=" << diff << endl; cout << "mul=" << mul << endl; } ==== やっとトランプの修正 ==== やっとトランプを修正するよ 前回いろいろアレだったところを、修正したので前のプログラムと入れ替えをする。 #include #include #include using std::cout; using std::endl; using std::cin; using std::string; //トランプ trump //4つのマークsuit -> //1~13の数字 //1->A 11->J 12->Q 13->K 表示されている数 // //トランプのカード1枚当たりのデータ struct aCard { //スペード:0 ハート:1 ダイヤ:2 クラブ:3 ジョーカー:4 int s_num; //カードの数字 1~13 + ジョーカー:0? int c_value; }; const int num_of_cards = 52; //13 * 4 struct aCard cards[num_of_cards];//13 * 4 各スートのカード + ババ 1枚 const string suit[5] = { "S", "H", "D", "C", "B" }; //空白はジョーカー用 //2~9,A,J,Q,Kの表示用文字 + ジョーカー B const string c_dsp_val[14] = { "B","A","2","3","4","5","6","7","8","9","10","J","Q","K" }; //カード1デッキにマークと数字をセットする関数 //第1引数 struct aCard* _c : カードを表す配列のポインタ(アドレス) //第2引数 int num : カードの枚数(多分53) void initCards(struct aCard* _c, int num) { for (int j = 0; j < 4; j++) { for (int i = 1; i <= 13; i++) { _c[j * 13 + i -1].s_num = j; _c[j * 13 + i -1].c_value = i; } } //_c [num_of_cards - 1].s_num = 4; //_c [num_of_cards-1].c_value = 0; } // void printaCard(struct aCard* _c) { //cout << (*_c).suit[(*_c).s_num] << (*_c).c_dsp_val[(*_c).c_value]; cout << suit[_c->s_num] << c_dsp_val[_c->c_value]; } //トランプのカードを並び順に一覧表示 void printAllCards(struct aCard* _c, int num) { for (int i = 0; i < num_of_cards; i++) { printaCard( _c + i ); cout << " "; } cout << endl; } //シャッフル=カードをばらばらにする。 //struct aCard cards[num_of_cards]; //cards[0]~cards[52]の53枚のカードがあるとき //これをシャッフルする方法を考えてください void shuffleCards(struct aCard* _c, int num) { //randを使ってどうにかしてカードをシャッフルする for (auto i = 0; i < 100; i++) { int s1 = rand() % num_of_cards; int s2 = rand() % num_of_cards; std::swap(_c[s1], _c[s2]); } } struct aCard popCard(struct aCard* _c, int num, int *cp) { if (*cp < num) { struct aCard tmp = _c[*cp]; (*cp)++; return tmp; } } // 関数名 calcCardPoint // 戻り値 intでカードの得点を計算して返す // ただし、BJの時は 0 を返す // 引数  カードの配列 struct aCard *_cards // カードの数 int num int calcCardPoint(struct aCard* _cards, int num) { カードが2枚の時はブラックジャックか、そうじゃないか そうじゃないときは、得点を返す カードがそれ以上の時は、合計得点を返す そん時に、絵札や、Aの数え方をかんがえなきゃないよね。 という、宿題。 (明日までにできるかな?) } int main() { int sp = 0;//デッキから配られたカード数 int p_card_n = 0;//プレイヤーの手持ちカード数 struct aCard p[10];//10枚分 srand((unsigned int)time(nullptr));//乱数の初期化 initCards(cards, num_of_cards); //カードを初期化 ////printAllCards(cards, num_of_cards);//カードを表示 shuffleCards(cards, num_of_cards);//カードをシャッフル //printAllCards(cards, num_of_cards);//カードを表示 p[0] = popCard(cards, num_of_cards, &sp); p_card_n++; p[1] = popCard(cards, num_of_cards, &sp); p_card_n++; for (int i = 0; i < p_card_n; i++) { printaCard(p + i); cout << " "; } cout << endl; int player_Point = 0; //bool bj = false; ////1枚目、または2枚目がA(エース)で+もう1枚が10以上のカードの時 //if ((p[0].c_value == 1 && p[1].c_value >= 10 ) // || (p[1].c_value == 1 && p[0].c_value >= 10)) //{ // bj = true; //} // //if (!bj) { // if (p[0].c_value <= 10) // { // if (p[0].c_value == 1) // player_Point += 11;//エースの時は11点 // else // player_Point += p[0].c_value;//それ以外はそのままの数を足す // } // else if (p[0].c_value == 11 || p[0].c_value == 12 || p[0].c_value == 13) // { // player_Point += 10; // } // if (p[1].c_value <= 10) // { // if(p[1].c_value == 1) // player_Point += 11;//エースの時は11点 // else // player_Point += p[1].c_value;//それ以外はそのまま // } // else if (p[1].c_value == 11 || p[1].c_value == 12 || p[1].c_value == 13) // { // player_Point += 10; // } //} player_Point = calcCardPoint(p, p_card_n); if (player_Point == 0) { cout << "Black Jack!" << endl; } else cout << "プレイヤーのカードの合計ポイントは" << player_Point << "です。" << endl; }