MENU

【C言語】クイズゲーム作成(8)問題数を増やす

クイズゲーム作成(8)問題数を増やす

こんにちは、コン(@pippi_kon)です。

この記事では『C言語でのクイズゲームの作り方』をご紹介しています。

前回は、クイズの問題数を増やすための前段階として、問題を外部ファイル(テキストファイル)から読み込む方法をご紹介しました。

今回は、クイズの問題数を増やす方法をご紹介します。

クイズ問題リスト(テキストファイル)に全部で10問登録し、その中からランダムで5問出題するという形式です。

OS:Windows 10(x64)
開発環境:Visual Studio 2019(Community)

目次

今回の目標

今回作成するプログラムの出力結果です。

クイズゲーム08_今回の目標

出題数から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の乱数を生成でき、今回追加したすべての問題が出題対象となります。

▲目次へ戻る

次回

準備中

▲目次へ戻る

created by Rinker
¥2,750 (2023/02/04 10:34:35時点 Amazon調べ-詳細)
created by Rinker
¥2,530 (2023/02/04 10:34:36時点 Amazon調べ-詳細)
  • URLをコピーしました!