LoginSignup
tyokom96
@tyokom96

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

なぜ論理和でなく論理積で正しく動くのか?

解決したいこと

visual stdio2022でじゃんけんゲームを作っていて正しい動き自体はするのですが、whileの条件式でなぜ論理和でなく論理積で動くのか気になったので知っている方教えてください。
c言語を使っています。
プログラミングを始めて1か月ほどなので初心者でも分かりやすい説明だと助かります。

該当するソースコード


#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>
#include<time.h>


int main(void) {
   int n;
   int b;
   b = 0;
   int c;
   c = 0;
   int a;
   a = 1;
   //5回戦の処理
   
        while( (b <= 2)&& (c <= 2))
       {
           //じゃんけんの入力
           
            printf("%d回戦目となります。\n", a);
            printf("勝ち%d\n",b);
            printf("負け%d\n", c);
            printf("1.グー2.チョキ3.パーのどれかを入力してください。数字以外または1,2,3の数字、マイナスの数字を入力すると強制終了されます。\n");
            printf("あいこはカウントされません。\n");
            scanf("%d", &n);
            if (n == 1) {
                   printf("あなたはグーを出しました\n");
            }
            if (n == 2) {
                   printf("あなたはチョキを出しました\n");
            }
            if (n == 3) {
                   printf("あなたはパーを出しました\n");
            }
            
           
            //1.2,3、以外の数字とマイナスの数字で強制終了
             if (n == 0 || n <= -1||n>=4) {
                   break;
             }
             //コンピューター側のじゃんけん
             int m;
             srand(time(NULL));
             int rn = rand();
             m = rn % 3 + 1;
             printf("出てきた乱数データは%d\n", rn);
             printf("コンピューターが入力したのは?%d\n", m);
             if (m == 1) {
                 printf("コンピューターはグーを出しました\n");
             }
             if (m == 2) {
                 printf("コンピューターはチョキを出しました\n");
             }
             if (m == 3) {
                 printf("コンピューターはパーを出しました\n");
             }
             //プレイヤーとコンピューターの比較
             if (n == m) {
                 printf("結果はあいこでした\n");
                 a = a - 1;
             }
             if (n == 1 && m == 2 || n == 2 && m == 3 || n == 3 && m == 1) {
                 printf("結果は勝ちでした\n");
                 b = b + 1;
             }
             if (n == 1 && m == 3 || n == 2 && m == 1 || n == 3 && m == 2) {
                 printf("結果は負けでした\n");
                 c = c + 1;
             }
             a = a + 1;
        }
    if (b == 3) {
       printf("あなたの勝ちです\n");
    }
    if (c == 3) {
       printf("コンピューターの勝ちです\n");
    }
    printf("じゃんけんを終了しました");
    getchar();
    return 0;
}

//疑問のコード while( (b <= 2)&& (c <= 2))
0

6Answer

bが2以下 OR cが2以下 という条件だと,勝ち数と負け数のどちらかが2以下だと条件を満たすことになりますよね.
具体的には3勝1敗になったら終わって欲しいけど,cが2以下という部分が条件を満たすのでwhileが終わってくれません.

2

Comments

  1. @tyokom96

    Questioner

    具体例を聞いてORだとダメな理由が分かりました。ありがとうございます!

  2. デバッガを使用するとこういった問題を1ステップずつ検証できるので良いです.今回のように条件式が上手く動いていなかったりしたら,変数の値の動きを追ってみてください.

    特定状況において脱出したいというような場合forやwhileは慣れるまでバグを書きやすいので,焦らず学習してください.

    ちなみにbreak使えば直感的なんじゃない?という話なんですが,少々根深い話になりなすので暇があれば読んでみてください.

  3. @tyokom96

    Questioner

    分かりました。ありがとうございます。

whlieのループはどちらかが3にカウントされたら抜ける条件に設定しよう思った

と言う話が,他者の回答へのコメント欄に存在していたため,そこのコメント欄に下記の内容を書いたのですが,そのような行為は許容されない旨のクレームをいただきましたので,該コメントは削除し,新規に「回答」という形で同様の内容を投稿する次第です.


どちらかが3にカウントされたら抜ける

という「ループを抜ける条件」を「ループを繰り返す条件」として言い換えるならば,「どちらも3ではないならば繰り返す」となりますよね.
これを bc を用いてより具体的に言えば「bが3ではなく,且つ,cも3ではない」となります.これをコード化すれば
while( (b!=3) && (c!=3) )
となりますよね.(この時点で && が現れます)

あとは「3ではない」というところを「2以下である」という形に変えれば
while( (b<=2) && (c<=2) )
となり,質問文内の条件と一致します.

2

Comments

  1. 質問内容とは直接関係ありませんが,個人的には

    while( 1 )
    {
      ...
    
      b = b + 1;  //bを変化させる処理
      if( b==3 )break;  //bの値次第で抜ける
    
      ...
    
      c = c + 1;  //cを変化させる処理
      if( c==3 )break;  //cの値次第で抜ける
    
      ...
    }
    

    みたく書けば,(考えている「抜ける条件」を直接的にコード化しているという意味で)わかりやすいのではないか? という気がします.

  2. @tyokom96

    Questioner

    すいません。while( 1 )が無限ループの処理とは知らなかったので思いつきませんでした。
    けど確かにこちらのコードの方が分かりやすいと思いました。勉強になります。

bcの変数が何を意味するのか知りませんが、

while((b <= 2) && (c <= 2)):bが2以下、かつ、cが2以下 の間、ループする。

while((b <= 2) || (c <= 2)):bが2以下、または、cが2以下 の間、ループする。

どちらが期待する動作ですか?

2

Comments

  1. @tyokom96

    Questioner

    while((b <= 2) || (c <= 2)):bが2以下、または、cが2以下 の間、ループする。
    こちらが期待する動作だったのですが実際は
    while((b <= 2) && (c <= 2)):bが2以下、かつ、cが2以下 の間、ループする。
    こちらの方で正しく動作したので疑問に思い、投稿させてもらいました。
    bがプレイヤーが勝った回数でcが負けた回数に設定しました。説明不足ですいません。

  2. while((b <= 2) || (c <= 2)):bが2以下、または、cが2以下 の間、ループする。
    こちらが期待する動作だったのです

    そうだとすると、ループを抜ける条件は、"bが3以上、かつ、cが3以上" ということになります。(正確には、"bが2より大きい、かつ、cが2より大きい" )
    これが期待する動作であれば、それでよいと思います。

    ループする条件の否定が、ループを抜ける条件です。

while の条件に使っている変数 b と c は何なのか、どういう事になったら while ループを抜けたいのか日本語で書きましょう。あなたが回答者に、

分かりやすい説明だと助かります。

と期待しているように、閲覧者も質問者に分かりやすい説明を期待してます。


【追記】

bがプレイヤーの勝った回数でcが負けた回数に設定しました。whlieのループはどちらかが3にカウントされたら抜ける条件に設定しよう思った

そうであれあば、質問欄に書かれたコード while((b <= 2) && (c <= 2)) の条件で良さそうに思いますが。

その条件では、b が 3 以上になると (b <= 2) は false になり、その場合は、&& を使っているので後の (c <= 2) は評価されずに while の ( ) 内は即 false になります。

b が 2 以下であれば (b <= 2) は true になります。その場合は && の後の (c <= 2) も評価され、c が 2 以下なら (c <= 2) は true になり while の ( ) 内は true に、c が 3 以上なら (c <= 2) は false になり while の ( ) 内は false なります。

それが望みの動きではないのですか?

while((b <= 2) || (c <= 2)) とすると、何百回勝っても 2 敗以下なら(逆に何百回負けても 2 勝以下なら)while の ( ) 内は true になってループは抜けられないということになるはずです。

1

Comments

  1. @tyokom96

    Questioner

    bがプレイヤーの勝った回数でcが負けた回数に設定しました。whlieのループはどちらかが3にカウントされたら抜ける条件に設定しよう思ったのですが自分の考え方とは違う処理で動いたので疑問に思い投稿させてもらいました。説明不足ですいません。

  2. 上のコメントは最初の質問欄を編集して追加情報として追記してください。他人の回答欄とそのコメント欄は読まない人も多いので。

    bがプレイヤーの勝った回数でcが負けた回数に設定しました。whlieのループはどちらかが3にカウントされたら抜ける条件に設定しよう思った

    そうであれあば、質問欄に書かれたコード while((b <= 2) && (c <= 2)) の条件で良さそうに思いますが。

    その条件では、b が 3 以上になると (b <= 2) は false になり、その場合は、&& を使っているので後の (c <= 2) は評価されずに while の ( ) 内は即 false になります。

    b が 2 以下であれば (b <= 2) は true になります。その場合は && の後の (c <= 2) も評価され、c が 2 以下なら (c <= 2) は true になり while の ( ) 内は true に、c が 3 以上なら (c <= 2) は false になり while の ( ) 内は false なります。

    それが望みの動きではないのですか?

    while((b <= 2) || (c <= 2)) とすると、何百回勝っても 2 敗以下なら(逆に何百回負けても 2 勝以下なら)while の ( ) 内は true になってループは抜けられないということになるはずです。

  3. @tyokom96

    Questioner

    説明を聞いて納得できました。ありがとうございます。

  4. 理解できたならこのスレッドはクローズしてください。

while( (b <= 2)&& (c <= 2)) を日本語で表現すると
「人が2勝以下 かつ CPUが2勝以下 の場合繰り返す」
だから動いているんじゃない?

これがちょっとわかりにくいなら
「人が3勝 または CPUが3勝したら 繰り返さない」
これなら論理和なので || になりますね

1

Comments

  1. @tyokom96

    Questioner

    分かりやすい説明ありがとうございます!下の条件をプログラムにしてみます!

  2. @vram さん

    「人が3勝 または CPUが3勝したら 繰り返さない」
    これなら論理和なので || になりますね

    || にすると、何百回勝っても 2 敗以下なら(逆に何百回負けても 2 勝以下なら)繰り返すことになると思いますけど。

  3. 答えを書くと学習にならないので答えは書きませんが
    条件が成立した場合「繰り返さない」と表現したのですが・・・

色々不慣れなところが多くてすいませんでした。なぜ論理積で動くのか理解できたのでクローズにします。教えてくれた方ありがとうございます!

0

Your answer might help someone💌