import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.HashSet;
/**
* 情報セキュリティマネジメント試験の合格確率をモンテカルロシミュレーションで計算するシミュレーター。
* 各問題の配点設定に基づいた「素点計算」により合格率を算出します。
* 本シミュレーターはIRT(項目応答理論)採点を再現するものではありません。
*/
public class IsmsSimulator {
// 情報セキュリティマネジメント試験の定数(素点計算に基づく)
private static final int TOTAL_QUESTIONS = 60; // 総問題数
private static final int DEFAULT_TRIALS = 10000; // 各シナリオでのデフォルト試行回数
// 合格に必要な合計得点
// 総合評価点600点以上 / 1000点 -> 100点満点中 (600/1000) * 100 = 60点
private static final int REQUIRED_TOTAL_SCORE = 60;
/**
* 各問題の定義。問題番号、選択肢の数、配点を保持します。
*/
public static class Question {
private final int no;
private final int choices;
private final int score;
public Question(int no, int choices, int score) {
this.no = no;
this.choices = choices;
this.score = score;
}
public int getNo() { return no; }
public int getChoices() { return choices; }
public int getScore() { return score; }
}
// 全60問の問題データ(No, 選択肢の数, 配点)
private static final List<Question> QUESTIONS = new ArrayList<>();
static {
// No. 1-48: 4択1点問題
for (int i = 1; i <= 48; i++) {
QUESTIONS.add(new Question(i, 4, 1));
}
// No. 49: 4択4点問題
QUESTIONS.add(new Question(49, 4, 4));
// No. 50: 8択4点問題
QUESTIONS.add(new Question(50, 8, 4));
// No. 51: 10択5点問題
QUESTIONS.add(new Question(51, 10, 5));
// No. 52: 8択4点問題
QUESTIONS.add(new Question(52, 8, 4));
// No. 53: 10択5点問題
QUESTIONS.add(new Question(53, 10, 5));
// No. 54: 6択4点問題
QUESTIONS.add(new Question(54, 6, 4));
// No. 55: 4択4点問題
QUESTIONS.add(new Question(55, 4, 4));
// No. 56: 5択4点問題
QUESTIONS.add(new Question(56, 5, 4));
// No. 57: 4択4点問題
QUESTIONS.add(new Question(57, 4, 4));
// No. 58: 9択5点問題
QUESTIONS.add(new Question(58, 9, 5));
// No. 59: 5択4点問題
QUESTIONS.add(new Question(59, 5, 4));
// No. 60: 10択5点問題
QUESTIONS.add(new Question(60, 10, 5));
}
/**
* ランダム解答方式を定義する列挙型。
* 各方式で、元の選択肢数から計算される有効な選択肢数を保持し、正答率を決定します。
*/
public enum AnswerMethod {
// 完全ランダム(不正解を0%消す力)
FULL_RANDOM("0%の不正解を消す力(完全ランダム)", 0.0),
// 不正解を25%消す力
ELIMINATE_25_PERCENT("25%の不正解を消す力", 0.25),
// 不正解を50%消す力
ELIMINATE_50_PERCENT("50%の不正解を消す力", 0.50);
private final String name;
private final double eliminationRate; // 除外する不正解の割合
AnswerMethod(String name, double eliminationRate) {
this.name = name;
this.eliminationRate = eliminationRate;
}
public String getName() {
return name;
}
/**
* 指定された問題の有効な選択肢数を計算します。
* Math.round() を使用し、最小値は1とします。
* @param originalChoices 元の選択肢の数
* @return 計算された有効な選択肢の数
*/
public int calculateEffectiveChoices(int originalChoices) {
// 除外後の選択肢数を計算
double remainingChoices = originalChoices * (1.0 - eliminationRate);
// Math.round で丸め、小数点以下を四捨五入して整数にする
int effectiveChoices = (int) Math.round(remainingChoices);
// 少なくとも1つの選択肢は残るようにする
return Math.max(1, effectiveChoices);
}
/**
* ランダムに正解するかどうかを判定します。
* @param random Randomインスタンス
* @param question 問題オブジェクト
* @return 正解であればtrue、そうでなければfalse
*/
public boolean isCorrect(Random random, Question question) {
int effectiveChoices = calculateEffectiveChoices(question.getChoices());
// 0からeffectiveChoices-1までの乱数を生成し、0であれば正解とみなす
return random.nextInt(effectiveChoices) == 0;
}
}
/**
* シミュレーション結果を保持するクラス。
*/
public static class SimulationResult {
private final int knownCorrectQuestions;
private final double successRate;
public SimulationResult(int knownCorrectQuestions, double successRate) {
this.knownCorrectQuestions = knownCorrectQuestions;
this.successRate = successRate;
}
public int getKnownCorrectQuestions() { return knownCorrectQuestions; }
public double getSuccessRate() { return successRate; }
}
private final Random random;
/**
* IsmsSimulator の新しいインスタンスを生成します。
*/
public IsmsSimulator() {
this.random = new Random();
}
/**
* 指定されたシナリオでモンテカルロシミュレーションを実行し、合格確率を計算します。
*
* @param answerMethod シミュレーション対象の解答方式(ランダム解答の精度)
* @param knownCorrectQuestions 事前に知っている正解数(60問全体に対する数)
* @param trials 試行回数
* @return シミュレーション結果を表す {@code SimulationResult} オブジェクト
* @throws IllegalArgumentException 不正な引数が指定された場合
*/
public SimulationResult simulateScenario(AnswerMethod answerMethod, int knownCorrectQuestions, int trials) {
if (knownCorrectQuestions < 0 || knownCorrectQuestions > TOTAL_QUESTIONS) {
throw new IllegalArgumentException(
"事前に知っている正解数 (" + knownCorrectQuestions + ") は、0から総問題数 (" + TOTAL_QUESTIONS + ") の範囲で指定してください。"
);
}
if (trials <= 0) {
throw new IllegalArgumentException("試行回数は1以上を指定してください。");
}
int successfulTrials = 0;
for (int i = 0; i < trials; i++) {
// 各問題の得点を格納する配列(インデックスは0から59にマップ)
int[] currentScores = new int[TOTAL_QUESTIONS];
// 既に「事前に知っている問題」としてマークされた問題のインデックスを保持
Set<Integer> knownCorrectIndices = new HashSet<>();
// 1. 「事前に知っている問題」の処理
List<Integer> questionIndices = new ArrayList<>();
for (int k = 0; k < TOTAL_QUESTIONS; k++) {
questionIndices.add(k);
}
Collections.shuffle(questionIndices, random); // 問題インデックスをシャッフル
// シャッフルされたリストからknownCorrectQuestions分だけ選び、正解とする
for (int k = 0; k < knownCorrectQuestions; k++) {
int questionIndex = questionIndices.get(k); // シャッフルされたインデックス
currentScores[questionIndex] = QUESTIONS.get(questionIndex).getScore(); // その問題の配点を加算
knownCorrectIndices.add(questionIndex); // 既に処理済みとしてマーク
}
// 2. 「残りの問題」の処理(ランダム解答)
for (int j = 0; j < TOTAL_QUESTIONS; j++) {
if (!knownCorrectIndices.contains(j)) { // 事前に知っている問題でなければランダムに解答
// その問題オブジェクトを取得
Question question = QUESTIONS.get(j);
if (answerMethod.isCorrect(random, question)) {
currentScores[j] = question.getScore(); // 正解なら配点を加算
} else {
currentScores[j] = 0; // 不正解なら0点
}
}
}
// 3. 合格条件の判定(総合評価のみ)
int totalEarnedScore = 0;
for (int score : currentScores) {
totalEarnedScore += score;
}
if (totalEarnedScore >= REQUIRED_TOTAL_SCORE) {
successfulTrials++;
}
}
double successRate = (double) successfulTrials / trials * 100;
return new SimulationResult(knownCorrectQuestions, successRate);
}
/**
* シミュレーション結果を表示します。
*
* @param result 表示するシミュレーション結果
*/
public void displayResult(SimulationResult result) {
System.out.printf("・事前に%d問知っている場合: 合格率: %.2f%%\n",
result.getKnownCorrectQuestions(), result.getSuccessRate());
}
/**
* メインメソッド。情報セキュリティマネジメント試験の各種シナリオでシミュレーションを実行します。
*/
public static void main(String[] args) {
IsmsSimulator simulator = new IsmsSimulator();
System.out.println("★情報セキュリティマネジメント試験 突破確率計算:ランダム選択方式(モンテカルロシミュレーション)★");
System.out.println("---");
System.out.println("総問題数: " + TOTAL_QUESTIONS + "問");
System.out.println("合格に必要な合計得点: " + REQUIRED_TOTAL_SCORE + "点 / 100点満点");
System.out.println("---");
System.out.println();
// 各解答方式のシミュレーション
for (AnswerMethod answerMethod : AnswerMethod.values()) {
System.out.println("■" + answerMethod.getName() + " 試行結果");
// knownCorrectQuestions は0問からTOTAL_QUESTIONSまで繰り返す
for (int i = 0; i <= TOTAL_QUESTIONS; i++) {
try {
SimulationResult result = simulator.simulateScenario(answerMethod, i, DEFAULT_TRIALS);
simulator.displayResult(result);
} catch (IllegalArgumentException e) {
System.err.println("エラー: " + e.getMessage());
}
}
System.out.println(); // 各解答方式の後に空行
}
System.out.println("---");
System.out.println("※本シミュレーターは、情報セキュリティマネジメント試験のIRT(項目応答理論)採点を厳密に再現するものではなく、");
System.out.println(" 各問題の配点が上記で設定された値であると仮定した「素点計算」に基づいています。");
System.out.println(" 実際の試験結果と異なる場合があることをご留意ください。");
}
}