こんにちは、コンジ(@pippi_kon)です。
この記事では『C言語でのクイズゲームの作り方』をご紹介しています。
前回は、クイズの問題数を増やすための前段階として、問題を外部ファイル(テキストファイル)から読み込む方法をご紹介しました。
今回は、クイズの問題数を増やす方法をご紹介します。
クイズ問題リスト(テキストファイル)に全部で10問登録し、その中からランダムで5問出題するという形式です。
今回の目標
今回作成するプログラムの出力結果です。
[第1問]
日本の国鳥は?
1:キジ 2:ハト 3:スズメ
>>> 1
正解!
[第2問]
大正->昭和->○○->令和
○○に入る年号は?
1:慶応 2:明治 3:平成
>>> 3
正解!
[第3問]
日本の歴史上、期間のいちばん長かった年号は?
1:明治 2:大正 3:昭和
>>> 1
不正解…
正解は 3:昭和 です。
[第4問]
99歳のことを何という?
1:喜寿 2:米寿 3:白寿
>>> 2
不正解…
正解は 3:白寿 です。
[第5問]
世界三大珍味はどれ?
1:イカスミ 2:キャビア 3:チーズ
>>> 2
正解!
–クイズ終了–
[第1問]…○
[第2問]…○
[第3問]…×
[第4問]…×
[第5問]…○
あなたは 5 問中 3 問正解でした (正答率:60 %)
出題数から3問から5問に増えています。
また、今までにはなかった問題が出題されています。
クイズ問題ファイルの中身
1 2 3 4 5 6 7 8 9 10 |
リンゴは英語で何と言う?,apple,orange,banana,1 大正->昭和->○○->令和\n○○に入る年号は?,慶応,明治,平成,3 世界三大珍味はどれ?,イカスミ,キャビア,チーズ,2 三角形の内角の和は?,90°,180°,360°,2 日本の初代総理大臣は誰?,伊藤博文,小泉純一郎,安倍晋三,1 甲子園球場がある都道府県は?,東京都,大阪府,兵庫県,3 日本の国鳥は?,キジ,ハト,スズメ,1 日本の歴史上、期間のいちばん長かった年号は?,明治,大正,昭和,3 ダイヤモンドは何でできている?,酸素,炭素,窒素,2 99歳のことを何という?,喜寿,米寿,白寿,3 |
前回から新たに7問追加し、全部で10問となりました。
プログラム全文
今回作成したプログラムのご紹介です。
のちほど、プログラムの解説を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
#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問出題するという形になっています。
プログラムの解説
最大問題数用定数の追加
7 8 |
#define QUIZ_NUM_MAX 10 #define QUIZ_NUM 5 |
クイズの最大問題数を指定する定数「QUIZ_NUM_MAX」を追加しました。
それぞれの定数の使用目的は以下の通り。
定数 | 使用目的 |
---|---|
QUIZ_NUM_MAX | すべての問題数 |
QUIZ_NUM | 出題する問題数 |
クイズを登録する構造体の容量アップ
54 |
quiz_t quiz[QUIZ_NUM_MAX]; |
quiz構造体にはすべてのクイズを登録します。
QUIZ_NUMのままだとすべて登録できないので、QUIZ_NUM_MAXに変更します。
クイズをランダム選択する範囲を変更
122 |
r = rand() % QUIZ_NUM_MAX; |
quiz構造体の全問題の中からランダム選択できるように範囲を変更します。
QUIZ_NUM → QUIZ_NUM_MAX
最後に
今回は、『クイズの問題数を増やす方法』をご紹介しました。
多くの問題の中からランダムで数問出題する…なんとなくクイズゲームっぽくなりましたね!
さらに問題数を増やしたい場合は、テキストファイルに問題を追加し、QUIZ_NUM_MAXの値を増やしてあげればOKです。
今回ご紹介した方法は、すべての問題をいったん構造体(メモリ)に登録し、その中からランダムで出題するという形式です。
作りはシンプルなのですが、問題数がどんどん増えていくと、その分メモリの使用量が増加してしまう欠点があります。
出題しない問題はメモリに保存しないような仕掛けにできるといいですね!
この辺りは次回以降ケアしていきます。
では今回はここまで。おつかれさまでした!
準備中

(2022/06/28 12:39:24時点 Amazon調べ-詳細)
(2022/06/28 12:39:25時点 Amazon調べ-詳細)