Skip to main content

第7回 正誤判定とゲーム化

🏆 第7回 正解判定を入れてゲームを完成させよう

HITとBLOWを表示できるようになりました。

最後に、入力が正解と一致したらループを終了し、正解メッセージを表示します。


1.文字列は == で比較しない

C言語の文字列は、char型の配列です。

次のように書いても、文字列の中身を正しく比較したことにはなりません。

if (answer == input)
{
    /* 正解 */
}

配列名は、配列の先頭位置として扱われるためです。

文字列の中身を比較するには、strcmpを使います。


2.ここでC言語: strcmp

strcmpは、2つの文字列を先頭から比較する関数です。

#include <string.h>
strcmp(answer, input)

戻り値は次のようになります。

戻り値 意味
0より小さい 1つ目の文字列が辞書順で前
0 2つの文字列が完全に一致
0より大きい 1つ目の文字列が辞書順で後

正解かどうかだけを確認する場合は、戻り値が0か調べます。

if (strcmp(answer, input) == 0)
{
    printf("正解です。\n");
}

3.ここでC言語: break

breakは、現在実行している繰返しを途中で終了します。

while (1)
{
    if (正解した)
    {
        break;
    }
}

breakを実行すると、whileの次の処理へ進みます。


4.入力ループを完成させる

入力エラーがない場合だけ、HITとBLOWを数えます。

結果を表示した後、文字列が完全に一致しているか確認します。

while (1)
{
    int error;
    int hit;
    int blow;

    printf("予想した4桁の数字を入力:");
    scanf("%254s", input);

    error = CheckAnswerError(input);

    if (error != 0)
    {
        ShowInputError(error);
    }
    else
    {
        hit = CountHit(answer, input);
        blow = CountBlow(answer, input);

        printf("HIT :%d\n", hit);
        printf("BLOW:%d\n", blow);

        if (strcmp(answer, input) == 0)
        {
            break;
        }
    }
}

printf("おめでとう!正解は%sでした。\n", answer);
printf("ゲーム終了!\n");

5.完成プログラム

#define _CRT_SECURE_NO_WARNINGS
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void MakeProblem(char answer[5])
{
    char temp[] = "0123456789";
    int i;

    for (i = 0; i < 100; i++)
    {
        int index1 = rand() % 10;
        int index2 = rand() % 10;
        char work;

        work = temp[index1];
        temp[index1] = temp[index2];
        temp[index2] = work;
    }

    for (i = 0; i < 4; i++)
    {
        answer[i] = temp[i];
    }

    answer[4] = '\0';
}

int CheckAnswerError(char input[])
{
    int i;
    int j;

    if (strlen(input) != 4)
    {
        return 1;
    }

    for (i = 0; i < 4; i++)
    {
        if (!isdigit((unsigned char)input[i]))
        {
            return 2;
        }
    }

    for (i = 0; i < 4; i++)
    {
        for (j = i + 1; j < 4; j++)
        {
            if (input[i] == input[j])
            {
                return 3;
            }
        }
    }

    return 0;
}

void ShowInputError(int error)
{
    if (error == 1)
    {
        printf("4桁で入力してください。\n");
    }
    else if (error == 2)
    {
        printf("0~9の数字だけを入力してください。\n");
    }
    else if (error == 3)
    {
        printf("同じ数字を2回使わないでください。\n");
    }
}

int CountHit(char answer[], char input[])
{
    int count = 0;
    int i;

    for (i = 0; i < 4; i++)
    {
        if (answer[i] == input[i])
        {
            count++;
        }
    }

    return count;
}

int CountBlow(char answer[], char input[])
{
    int count = 0;
    int i;
    int j;

    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
        {
            if (input[i] == answer[j] && i != j)
            {
                count++;
            }
        }
    }

    return count;
}

int main(void)
{
    char answer[5];
    char input[255];

    srand((unsigned int)time(NULL));
    MakeProblem(answer);

    printf("HIT & BLOW GAME\n");
    printf("ゲーム開始!\n");

    /* デバッグ中は次の行を有効にすると確認しやすい */
    /* printf("正解:%s\n", answer); */

    while (1)
    {
        int error;
        int hit;
        int blow;

        printf("\n予想した4桁の数字を入力:");
        scanf("%254s", input);

        error = CheckAnswerError(input);

        if (error != 0)
        {
            ShowInputError(error);
        }
        else
        {
            hit = CountHit(answer, input);
            blow = CountBlow(answer, input);

            printf("HIT :%d\n", hit);
            printf("BLOW:%d\n", blow);

            if (strcmp(answer, input) == 0)
            {
                break;
            }
        }
    }

    printf("\nおめでとう!正解は%sでした。\n", answer);
    printf("ゲーム終了!\n");

    return 0;
}


6.疑似言語と完成コードを比べる

○ HIT_AND_BLOW

  ・問題を作る

  ■ hit ≠ 4
  │ ・4桁を入力する
  │ ・入力エラーを調べる
  │
  │ ▲ 入力エラーがある
  │ │ ・入力エラーを表示する
  │ ├────────────────
  │ │ ・HITとBLOWを数える
  │ │ ・HITとBLOWを表示する
  │ ▼
  ■

  ・正解メッセージを表示する

疑似言語で考えた処理が、それぞれ関数やifwhileとしてC言語へ置き換わりました。


7.ゲームを発展させよう

完成後は、次の機能を追加できます。

  • 正解までの挑戦回数を表示する
  • 過去の入力とHIT・BLOWを履歴として表示する
  • 入力エラーごとに詳しい説明を出す
  • 桁数を変更できるようにする
  • タイトル画面や結果画面を付ける
  • 関数を別の.cファイルへ分ける
  • ヘッダーファイルを作る
  • DxLibなどを使ってグラフィック付きにする


🏁 全7回のまとめ

このゲーム制作では、次のC言語の仕組みを使用しました。

  • char型の配列による文字列
  • 終端文字\0
  • strlenによる文字数確認
  • randsrandによる乱数
  • 配列要素の交換
  • 配列を関数へ渡す方法
  • whileによる入力ループ
  • returnによるエラー番号の返却
  • isdigitによる数字判定
  • 二重ループによる重複・BLOW判定
  • strcmpによる文字列比較
  • breakによるループ終了

最初に作った疑似言語の流れを、少しずつC言語へ変換することで、HIT&BLOWゲームが完成しました。