こんにちは、コン(@pippi_kon)です。
この記事では『C言語でのクイズゲームの作り方』をご紹介しています。
前回は、クイズの問題数を増やすための前段階として、問題を外部ファイル(テキストファイル)から読み込む方法をご紹介しました。
今回は、クイズの問題数を増やす方法をご紹介します。
クイズ問題リスト(テキストファイル)に全部で10問登録し、その中からランダムで5問出題するという形式です。
今回の目標
今回作成するプログラムの出力結果です。
出題数から3問から5問に増えています。
また、今までにはなかった問題が出題されています。
クイズ問題ファイルの中身
リンゴは英語で何と言う?,apple,orange,banana,1
大正->昭和->○○->令和\n○○に入る年号は?,慶応,明治,平成,3
世界三大珍味はどれ?,イカスミ,キャビア,チーズ,2
三角形の内角の和は?,90°,180°,360°,2
日本の初代総理大臣は誰?,伊藤博文,小泉純一郎,安倍晋三,1
甲子園球場がある都道府県は?,東京都,大阪府,兵庫県,3
日本の国鳥は?,キジ,ハト,スズメ,1
日本の歴史上、期間のいちばん長かった年号は?,明治,大正,昭和,3
ダイヤモンドは何でできている?,酸素,炭素,窒素,2
99歳のことを何という?,喜寿,米寿,白寿,3
前回から新たに7問追加し、全部で10問となりました。
プログラム全文
今回作成したプログラムのご紹介です。
のちほど、プログラムの解説を行います。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define QUIZ_NUM_MAX 10
#define QUIZ_NUM 5
#define FLAG_ON 1
#define FLAG_OFF 0
#define QUESTION_FILE "questions.txt"
typedef struct {
char mondai[100];
char sentaku[3][100];
int answer_no;
int done_flag;
}quiz_t;
void set_quiz(quiz_t* t, char* m, char* s1, char* s2, char* s3, int a)
{
strncpy(t->mondai, m, sizeof(t->mondai));
strncpy(t->sentaku[0], s1, sizeof(t->sentaku[0]));
strncpy(t->sentaku[1], s2, sizeof(t->sentaku[1]));
strncpy(t->sentaku[2], s3, sizeof(t->sentaku[2]));
t->answer_no = a;
t->done_flag = FLAG_OFF;
}
void change_kaigyou(char* s)
{
char* p;
char* w;
while (1) {
p = strstr(s, "\\n");
if (p == NULL) {
return;
}
*p = '\n';
*p++;
w = p;
*w++;
while (*p++ = *w++);
}
}
int main(void)
{
int ans;
char result[QUIZ_NUM][10];
int ok_cnt = 0;
int i;
quiz_t quiz[QUIZ_NUM_MAX];
int r;
FILE* fp;
int set_quiz_error_flag = FLAG_OFF;
char line[1000];
char* ptr_mondai;
char* ptr_sentaku1;
char* ptr_sentaku2;
char* ptr_sentaku3;
char* ptr_answer_no;
fp = fopen(QUESTION_FILE, "r");
if (fp == NULL) {
printf("問題リストのオープンに失敗しました。ファイル名 = %s\n", QUESTION_FILE);
return -1;
}
i = 0;
while (fgets(line, sizeof(line), fp) != NULL) {
change_kaigyou(line);
ptr_mondai = strtok(line, ",");
if (ptr_mondai == NULL) {
printf("問題文の登録に失敗しました。ファイル名 = %s, 行数 = %d\n", QUESTION_FILE, i + 1);
set_quiz_error_flag = FLAG_ON;
break;
}
ptr_sentaku1 = strtok(NULL, ",");
if (ptr_sentaku1 == NULL) {
printf("選択肢1の登録に失敗しました。ファイル名 = %s, 行数 = %d\n", QUESTION_FILE, i + 1);
set_quiz_error_flag = FLAG_ON;
break;
}
ptr_sentaku2 = strtok(NULL, ",");
if (ptr_sentaku2 == NULL) {
printf("選択肢2の登録に失敗しました。ファイル名 = %s, 行数 = %d\n", QUESTION_FILE, i + 1);
set_quiz_error_flag = FLAG_ON;
break;
}
ptr_sentaku3 = strtok(NULL, ",");
if (ptr_sentaku3 == NULL) {
printf("選択肢3の登録に失敗しました。ファイル名 = %s, 行数 = %d\n", QUESTION_FILE, i + 1);
set_quiz_error_flag = FLAG_ON;
break;
}
ptr_answer_no = strtok(NULL, ",");
if (ptr_answer_no == NULL) {
printf("正解の登録に失敗しました。ファイル名 = %s, 行数 = %d\n", QUESTION_FILE, i + 1);
set_quiz_error_flag = FLAG_ON;
break;
}
set_quiz(&quiz[i], ptr_mondai, ptr_sentaku1, ptr_sentaku2, ptr_sentaku3, atoi(ptr_answer_no));
i++;
}
fclose(fp);
if (set_quiz_error_flag == FLAG_ON) {
return -1;
}
srand((unsigned int)time(NULL));
i = 0;
while (i < QUIZ_NUM) {
r = rand() % QUIZ_NUM_MAX;
if (quiz[r].done_flag == FLAG_ON) {
continue;
}
printf("[第%d問]\n", i + 1);
printf("%s\n", quiz[r].mondai);
printf("1:%s 2:%s 3:%s\n", quiz[r].sentaku[0], quiz[r].sentaku[1], quiz[r].sentaku[2]);
printf(">>> ");
scanf("%d", &ans);
if (ans == quiz[r].answer_no) {
printf("正解!\n\n");
strncpy(result[i], "○", sizeof(result[i]));
ok_cnt++;
}
else {
printf("不正解...\n");
printf("正解は %d:%s です。\n\n", quiz[r].answer_no, quiz[r].sentaku[quiz[r].answer_no - 1]);
strncpy(result[i], "×", sizeof(result[i]));
}
quiz[r].done_flag = FLAG_ON;
i++;
}
printf("--クイズ終了--\n");
for (i = 0; i < QUIZ_NUM; i++) {
printf("[第%d問]...%s\n", i + 1, result[i]);
}
printf("あなたは %d 問中 %d 問正解でした (正答率:%d %%)\n", QUIZ_NUM, ok_cnt, (ok_cnt * 100) / QUIZ_NUM);
return 0;
}
今回のプログラムでは、すべての問題をいったん構造体配列に格納し、その中からランダムで5問出題するという形になっています。
プログラムの解説
最大問題数用定数の追加
#define QUIZ_NUM_MAX 10
#define QUIZ_NUM 5
クイズの最大問題数を指定する定数「QUIZ_NUM_MAX」を追加しました。
それぞれの定数の使用目的は以下の通り。
定数 | 使用目的 |
---|---|
QUIZ_NUM_MAX | すべての問題数 |
QUIZ_NUM | 出題する問題数 |
クイズを登録する構造体の容量アップ
quiz_t quiz[QUIZ_NUM_MAX];
quiz構造体にはすべてのクイズを登録します。
QUIZ_NUMのままだとすべて登録できないので、QUIZ_NUM_MAXに変更します。
クイズをランダム選択する範囲を変更
r = rand() % QUIZ_NUM_MAX;
quiz構造体の全問題の中からランダム選択できるように範囲を変更します。
「QUIZ_NUM」のままだと、今回だと0~4の乱数しか取得できず、出題対象とならない問題がでてきます。
「QUIZ_NUM_MAX」にすることで、0~9の乱数を生成でき、今回追加したすべての問題が出題対象となります。
次回
準備中