タイピング・ゲーム

| Topic path: Top / 授業 / C言語基礎 / タイピング・ゲーム

*文字列の比較 [#i7591004]

string.h には、文字列を比較するstrcmp関数が用意されています。

strcmp関数は、引数として二つの文字列 s1 と s2 を受け取り、辞書式に比較します。
s1 > s2(辞書で s1 が s2 より後に載る場合)ならば正の値、s1 < s2(辞書で s1 が s2 より先に載る場合)ならば負の値、s1 = s2(s1 と s2 が同じ文字列の場合)ならば 0 を返します(プログラム1)。
#geshi(c){{
#include <stdio.h>
#include <string.h>
#include <time.h>

int main(void) {
  char s1[256], s2[256];

  printf("メール・アドレスを入力してください:\n");
  scanf("%s", s1)

  printf("もう一度入力してください:\n");
  scanf("%s", s2)

  if (strcmp(s1, s2) == 0) {
    printf("OK\n");
  } else {
    printf("NG\n");
  }

  return 0;
}
}}


*文字列のコピー(代入) [#e7d8fee4]

string.h には、文字列をコピー(代入)するstrcpy関数が用意されています。

strcpy関数は、引数として二つの文字列 s1 と s2 を受け取り、文字列 s1 に文字列 s2 をコピー(代入)します。(プログラム2)。
#geshi(c){{
#include <stdio.h>
#include <string.h>
#include <time.h>

int main(void) {
  char s1[256], s2[256];

  printf("メール・アドレスを入力してください:\n");
  scanf("%s", s2)

  strcpy(s1, s2);
  printf("%s\n", s1);

  return 0;
}
}}


*タイピング・ゲーム [#b5e294ed]

ランダムに文字列を出題し、キーボードから入力された文字列と比較して正解か間違いかを判定します(プログラム3)。
#geshi(c){{
/*
 *  タイピング・ゲーム
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int main(void) {
  char s[256];
  char ans[10][256] = {
    "cat",
    "dog",
    "lion",
    "bear",
    "tiger",
    "monkey",
    "giraffe",
    "elephant",
    "kangaroo",
    "hippopotamus"
  };

  srand((unsigned int) time(NULL));
  int r = rand() % 10;

  printf("%s:\n", ans[r]);
  scanf("%s", s);
  if (strcmp(s, ans[r]) == 0) {
    printf("正解!\n");
  } else {
    printf("間違い!\n");
  }

  return 0;
}
}}


*繰り返しタイピング・ゲーム [#a4a0a2cd]

タイピング・ゲームを改良し、10問出題して正解数を出力するようにしてみましょう。
#geshi(c){{
/*
 *  繰り返しタイピング・ゲーム
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int main(void) {
  char s[256];
  char ans[10][256] = {
    "cat",
    "dog",
    "lion",
    "bear",
    "tiger",
    "monkey",
    "giraffe",
    "elephant",
    "kangaroo",
    "hippopotamus"
  };

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

  int score = 0;  // 得点
  int i;
  for (i = 1; i <= 10; i++) {
    int r = rand() % 10;

    printf("第%d問: %s:\n", i, ans[r]);
    scanf("%s", s);
    if (strcmp(s, ans[r]) == 0) {
      printf("正解!\n");
      score++;
    } else {
      printf("間違い!\n");
    }
  }
  printf("%d問正解\n", score);

  return 0;
}
}}


*スピード・タイピング・ゲーム [#zae0a50c]
次に、スピード計算ゲームと同じように、制限時間内に何問正解できるかを競うゲームにしてみましょう。
#geshi(c){{
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int main(void) {
  char s[256];
  char ans[10][256] = {
    "cat",
    "dog",
    "lion",
    "bear",
    "tiger",
    "monkey",
    "giraffe",
    "elephant",
    "kangaroo",
    "hippopotamus"
  };

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

  long limit = 30;      // 制限時間(秒)
  printf("制限時間: %d秒\n", limit);

  long t = time(NULL);  // 開始時刻
  int score = 0;        // 得点
  while (time(NULL) < t + limit) {
    int r = rand() % 10;

    printf("第%d問: %s:\n", score + 1, ans[r]);
    scanf("%s", s);

    if (time(NULL) > t + limit) { break; }  // 時間切れ

    if (strcmp(s, ans[r]) == 0) {
      printf("正解!\n");
      score++;
    } else {
      printf("間違い!\n");
    }
  }
  printf("%d問正解\n", score);

  return 0;
}
}}

*モジュール化 [#zcddbaaf]

プログラムを組み合わせて、いろいろな問題のタイピング・ゲームが作れるように、問題を作成する部分をモジュール化します。

まず、モジュールごとにファイルを分割します。
#geshi(c){{
/*
 *  typing.h
 */
#define SIZE 10
#define MAX_LENGTH 256
}}

#geshi(c){{
/*
 *  animal.c
 */
#include <string.h>
#include "typing.h"

int getans(char ans[][MAX_LENGTH]) {
  char s[SIZE][MAX_LENGTH] = {
    "cat",
    "dog",
    "lion",
    "bear",
    "tiger",
    "monkey",
    "giraffe",
    "elephant",
    "kangaroo",
    "hippopotamus"
  };

  int i;
  for (i = 0; i < SIZE; i++) {
    strcpy(ans[i], s[i]);
  }

  return 0;
}
}}
#geshi(c){{
/*
 *  typing.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "typing.h"

extern int getans(char [][MAX_LENGTH]);

int main(void) {
  char s[MAX_LENGTH];
  char ans[SIZE][MAX_LENGTH];

  getans(ans);
  srand((unsigned int) time(NULL));

  long limit = 30;      // 制限時間(秒)
  printf("制限時間: %d秒\n", limit);

  long t = time(NULL);  // 開始時刻
  int score = 0;        // 得点
  while (time(NULL) < t + limit) {
    int r = rand() % SIZE;

    printf("第%d問: %s:\n", score + 1, ans[r]);
    scanf("%s", s);

    if (time(NULL) > t + limit) { break; }  // 時間切れ

    if (strcmp(s, ans[r]) == 0) {
      printf("正解!\n");
      score++;
    } else {
      printf("間違い!\n");
    }
  }
  printf("%d問正解\n", score);

  return 0;
}
}}

すると、ファイルごとにコンパイルできます。
#geshi(sh){{
luna% gcc -c animal.c
luna% gcc -c typing.c
luna% gcc -o typing typing.o animal.o
}}

そこで、別の問題作成モジュールを用意します。
#geshi(c){{
/*
 *  country.c
 */
#include <string.h>
#include "typing.h"

int getans(char ans[][MAX_LENGTH]) {
  char s[SIZE][MAX_LENGTH] = {
    "UK",
    "USA",
    "Japan",
    "Italy",
    "Canada",
    "French",
    "Germany",
    "China",
    "Korea",
    "Russia"
  };

  int i;
  for (i = 0; i < SIZE; i++) {
    strcpy(ans[i], s[i]);
  }

  return 0;
}
}}

このファイルも、このファイルだけでコンパイルでき、すでにコンパイルしてある本体モジュールと組み合わせることができます。
#geshi(sh){{
luna% gcc -c country.c
luna% gcc -o typing typing.o county.o
}}


*二次元配列を関数の引数にするときの注意(おまけ) [#d7fdc876]

配列を関数の引数にするときは、要素数は無視され、省略できます。
#geshi(c){{
int sum(int a[], int n) {
  int i, s = 0;
  for (i = 0; i < n; i++) {
    s += a[i]
  }
  return s;
}
}}

配列の要素数を省略できるのは、要素の型が分かっていれば要素のサイズを調べることができるので、配列の要素にアクセスするときに、配列の先頭アドレスに要素番号と要素のサイズを掛けたものを加えることで目的の要素のアドレスを計算できるからです。
たとえば、int型が32ビットのとき、int型の配列における要素番号10の要素は先頭アドレスから320ビット後にあります。
たとえば、int型が32ビットのとき、int型の配列 a における要素番号10の要素 a[10] は先頭アドレスから320ビット後にあることがわかり、この計算に配列の要素数は必要ありません。

ところが、二次元配列を関数の引数にするときは、高次元配列の要素数は省略できますが、低次元配列の要素数は省略できません。
#geshi(c){{
int sum(int a[][100], int n) {
  int i, j, s = 0;
  for (i = 0; i < n; i++) {
    for (j = 0; j < 100; j++) {
      s += a[i][j];
    }
  }
  return s;
}
}}

二次元配列で低次元配列の要素数が省略されていると、目的の要素のアドレスが計算できません。
たとえば、int型が32ビットのとき、int型の二次元配列における高次元の要素番号10、低次元の要素番号10の要素は、先頭アドレスから低次元配列のサイズ*10+320ビット後にあります。
二次元配列で低次元配列の要素数が省略されていると、低次元配列のサイズが計算できないため、目的の要素のアドレスが計算できません。
たとえば、int型が32ビットのとき、int型の二次元配列 a における高次元の要素番号5、低次元の要素番号10の要素 a[5][10] は、先頭アドレスから低次元配列のサイズ*5+320ビット後にあると計算できます。
そのため、低次元配列の要素数は省略できません。
トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS