junkerstock
 quiz-perl初級50本ノック 

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Perl初級 50本ノック</title>
<style>
:root {
/* 初級編:若葉と青空のフレッシュなイメージ */
--primary-color: #2e7d32; /* Green */
--secondary-color: #0277bd; /* Light Blue */
--accent-color: #fdd835; /* Yellow */
--correct-color: #00c853;
--incorrect-color: #d32f2f;
--light-bg: #e8f5e9;
--white-bg: #ffffff;
--text-color: #37474f;
--highlight-bg: #c8e6c9;
}
body {
font-family: 'Hiragino Kaku Gothic ProN', 'Hiragino Sans', Meiryo, sans-serif;
background-color: var(--light-bg);
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
padding: 20px 0;
}
#container {
width: 95%;
max-width: 900px;
}
.panel {
background-color: var(--white-bg);
border-radius: 12px;
box-shadow: 0 8px 25px rgba(0,0,0,0.1);
padding: 25px;
text-align: center;
margin-bottom: 20px;
border-top: 6px solid var(--primary-color);
}
.hidden { display: none !important; }

h1 {
color: var(--primary-color);
margin-bottom: 0.5rem;
font-size: 1.6rem;
text-shadow: 1px 1px 0px rgba(0,0,0,0.05);
}

#question-number {
font-size: 14px;
font-weight: bold;
color: var(--secondary-color);
margin-bottom: 10px;
text-transform: uppercase;
letter-spacing: 1px;
}

/* プログレスバー */
#progress-bar {
width: 100%;
height: 10px;
background-color: #cfd8dc;
border-radius: 5px;
margin-bottom: 20px;
overflow: hidden;
}
#progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
width: 0%;
transition: width 0.3s ease;
}

#question {
font-size: 20px;
font-weight: 600;
min-height: 60px;
margin: 10px 0 25px;
line-height: 1.6;
text-align: left;
border-bottom: 2px solid #f1f8e9;
padding-bottom: 15px;
}

code {
background-color: #f1f8e9;
padding: 2px 6px;
border-radius: 4px;
font-family: Consolas, Monaco, monospace;
color: #d81b60;
font-size: 0.95em;
border: 1px solid #c5e1a5;
}

#options {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
margin: 15px 0;
}
@media (min-width: 600px) {
#options { grid-template-columns: 1fr 1fr; }
}

.option {
background: var(--white-bg);
color: var(--text-color);
border: 2px solid #b0bec5;
border-radius: 8px;
padding: 15px;
font-size: 16px;
cursor: pointer;
transition: all 0.2s;
text-align: left;
position: relative;
font-weight: 500;
}
.option:hover:not(:disabled) {
border-color: var(--primary-color);
background-color: #f1f8e9;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.option:disabled { cursor: default; opacity: 0.7; }

/* 正誤判定スタイル */
.option.correct-choice {
background-color: var(--correct-color) !important;
color: white !important;
border-color: var(--correct-color) !important;
}
.option.incorrect-choice {
background-color: var(--incorrect-color) !important;
color: white !important;
border-color: var(--incorrect-color) !important;
}
.option.correct-answer {
background-color: white !important;
color: var(--correct-color) !important;
border-color: var(--correct-color) !important;
border-width: 3px;
font-weight: bold;
}
.option.correct-answer::after {
content: "◎";
position: absolute;
right: 15px;
font-weight: bold;
}

#feedback-area {
background-color: var(--highlight-bg);
border-radius: 8px;
padding: 20px;
margin-top: 20px;
text-align: left;
border-left: 6px solid var(--primary-color);
animation: fadeIn 0.4s;
}
@keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }

#feedback-title { font-weight: bold; font-size: 1.2em; margin-bottom: 8px; }
.fb-correct { color: var(--correct-color); }
.fb-incorrect { color: var(--incorrect-color); }

#next-button, .action-button {
background-color: var(--primary-color);
color: white;
border: none;
border-radius: 30px;
padding: 12px 40px;
font-size: 16px;
cursor: pointer;
margin-top: 15px;
display: inline-block;
transition: background 0.3s, transform 0.1s;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
#next-button:hover, .action-button:hover {
background-color: #1b5e20;
transform: scale(1.05);
}
#next-button { display: block; margin: 20px auto 0; }

#timer-area { margin-top: 20px; font-weight: bold; color: #78909c; font-size: 1em; }

/* 結果画面 */
#score-display { font-size: 3.5rem; font-weight: bold; color: var(--primary-color); margin: 20px 0; }
#result-message { font-size: 1.2rem; margin-bottom: 20px; }
#explanation-list {
text-align: left;
max-height: 60vh;
overflow-y: auto;
margin-top: 25px;
padding: 15px;
border: 1px solid #cfd8dc;
background: #fff;
border-radius: 8px;
}
.review-item { border-bottom: 1px solid #eee; padding: 15px 0; font-size: 0.95em; }
.review-q { font-weight: bold; margin-bottom: 8px; color: #37474f; }
.review-status.ok { color: var(--correct-color); font-weight: bold; margin-right: 5px; }
.review-status.ng { color: var(--incorrect-color); font-weight: bold; margin-right: 5px; }
.review-ans { color: #546e7a; font-size: 0.9em; margin-top: 4px; }
</style>
</head>
<body>

<div id="container">
<div id="quiz-area" class="panel">
<h1 id="main-title"></h1>
<div id="progress-bar"><div id="progress-fill"></div></div>
<div id="question-number"></div>
<div id="question"></div>
<div id="options"></div>

<div id="feedback-area" class="hidden">
<div id="feedback-title"></div>
<div id="feedback-text"></div>
<button id="next-button">次へ ❯</button>
</div>

<div id="timer-area">残り時間: <span id="timer"></span>秒</div>
</div>

<div id="result-area" class="panel hidden">
<h2>結果発表</h2>
<div id="score-display"></div>
<div id="result-message"></div>
<button id="restart-button" class="action-button">最初からやり直す</button>
<div id="explanation-list"></div>
</div>
</div>

<script>
'use strict';

// 設定
const CONFIG = {
title: "Perl初級 50本ノック",
timerSeconds: 30, // 初級なのでサクサク進める時間設定
};

// 状態管理
let state = {
questions: [],
currentIndex: 0,
score: 0,
timer: null,
timeLeft: 0,
userAnswers: []
};

// DOM要素
const els = {
quizArea: document.getElementById('quiz-area'),
resultArea: document.getElementById('result-area'),
mainTitle: document.getElementById('main-title'),
progressFill: document.getElementById('progress-fill'),
qNum: document.getElementById('question-number'),
qText: document.getElementById('question'),
options: document.getElementById('options'),
feedbackArea: document.getElementById('feedback-area'),
fbTitle: document.getElementById('feedback-title'),
fbText: document.getElementById('feedback-text'),
nextBtn: document.getElementById('next-button'),
timerArea: document.getElementById('timer-area'),
timer: document.getElementById('timer'),
scoreDisplay: document.getElementById('score-display'),
resultMsg: document.getElementById('result-message'),
reviewList: document.getElementById('explanation-list'),
restartBtn: document.getElementById('restart-button')
};

// クイズデータ (全50問)
const ALL_QUESTIONS = [
// --- 基本概念と変数 (1-10) ---
{ q: "Perlのスクリプトで、安全なプログラミングのために最初に記述すべき2つの行(プラグマ)は?", o: ["use strict; use warnings;", "use safe; use secure;", "use perl; use english;", "import std; import io;"], a: 0, exp: "<code>use strict;</code> は厳密な文法チェック、<code>use warnings;</code> は警告を表示します。モダンPerlの基本です。" },
{ q: "Perlにおける「スカラ変数(単一の値)」を表す記号(シジル)は?", o: ["$", "@", "%", "&"], a: 0, exp: "スカラ変数は <code>$variable</code> のように <code>$</code> で始まります。" },
{ q: "Perlにおける「配列(順序付きリスト)」を表す記号(シジル)は?", o: ["@", "$", "%", "*"], a: 0, exp: "配列変数は <code>@array</code> のように <code>@</code> で始まります。" },
{ q: "Perlにおける「ハッシュ(連想配列)」を表す記号(シジル)は?", o: ["%", "@", "$", "#"], a: 0, exp: "ハッシュ変数は <code>%hash</code> のように <code>%</code> で始まります。" },
{ q: "行末までをコメントアウトするために使う文字は?", o: ["#", "//", "/*", "--"], a: 0, exp: "Perlのコメントは <code>#</code> から行末までです。" },
{ q: "文(ステートメント)の終わりを表す必須の文字は?", o: ["; (セミコロン)", ": (コロン)", ". (ピリオド)", ", (カンマ)"], a: 0, exp: "C言語などと同様、文末には <code>;</code> が必要です。" },
{ q: "ダブルクォート <code>\"...\"</code> とシングルクォート <code>'...'</code> の主な違いは?", o: ["ダブルクォートは変数展開やエスケープ文字を解釈する", "シングルクォートの方が高機能", "違いはない", "シングルクォートは数値を表す"], a: 0, exp: "<code>\"Hello $name\"</code> は変数が展開されますが、<code>'Hello $name'</code> はそのまま文字として表示されます。" },
{ q: "文字列を連結するための演算子は?", o: [". (ドット)", "+ (プラス)", "& (アンパサンド)", "~ (チルダ)"], a: 0, exp: "Perlでの文字列連結は <code>$str1 . $str2</code> のようにドットを使います。" },
{ q: "文字列を繰り返す(例: 'A'を5回)ための演算子は?", o: ["x", "*", "^", "repeat"], a: 0, exp: "<code>'A' x 5</code> で 'AAAAA' になります。" },
{ q: "変数の内容を表示する最も基本的な関数は?", o: ["print", "echo", "write", "puts"], a: 0, exp: "<code>print \"Hello\";</code> のように使います。" },

// --- 配列とハッシュ (11-20) ---
{ q: "配列 <code>@colors</code> の「最初の要素」にアクセスする書き方は?", o: ["$colors[0]", "@colors[0]", "$colors{0}", "@colors{0}"], a: 0, exp: "配列の要素1つを取り出すとスカラになるため、<code>$</code> を使い、添字は <code>[]</code> で指定します。" },
{ q: "配列の「最後」に要素を追加する関数は?", o: ["push", "pop", "unshift", "shift"], a: 0, exp: "<code>push(@array, 'new');</code> で末尾に追加します。" },
{ q: "配列の「最後」から要素を取り出す(削除する)関数は?", o: ["pop", "push", "delete", "remove"], a: 0, exp: "<code>pop(@array)</code> は末尾の要素を取り出して返します。" },
{ q: "配列の「先頭」から要素を取り出す関数は?", o: ["shift", "unshift", "head", "top"], a: 0, exp: "<code>shift(@array)</code> は先頭の要素を取り出し、配列全体を左にずらします。" },
{ q: "ハッシュ <code>%scores</code> のキー 'math' に対応する値を取得する書き方は?", o: ["$scores{'math'}", "%scores{'math'}", "@scores['math']", "$scores->math"], a: 0, exp: "ハッシュの要素もスカラなので <code>$</code> を使い、キーは <code>{}</code> で囲みます。" },
{ q: "ハッシュを定義する際、キーと値のペアを見やすく書くために使われる記号 <code>=></code> の通称は?", o: ["ファットカンマ (Fat Comma)", "アロー演算子", "ダブルアロー", "ハッシュロケット"], a: 0, exp: "<code>key => 'value'</code> のように書きます。機能はカンマとほぼ同じですが、左側のクォートを省略できます。" },
{ q: "ハッシュの「すべてのキー」をリストとして取得する関数は?", o: ["keys", "values", "each", "list"], a: 0, exp: "<code>keys %hash</code> でキーの一覧を取得できます。" },
{ q: "配列 <code>@items</code> の要素数(サイズ)を知るための一般的な方法は?", o: ["scalar(@items)", "count(@items)", "length(@items)", "size(@items)"], a: 0, exp: "配列をスカラコンテキストで評価する(<code>scalar</code>関数を使う、またはスカラ変数に代入する)と要素数が返ります。" },
{ q: "スペース区切りの単語リストを簡単に配列にする構文 <code>qw(...)</code> の意味は?", o: ["Quote Words", "Quick Write", "Queue Wait", "Query Where"], a: 0, exp: "<code>qw(apple banana cherry)</code> は <code>('apple', 'banana', 'cherry')</code> と同じ意味になります。" },
{ q: "範囲演算子を使って 1 から 10 までの配列を作る書き方は?", o: ["(1..10)", "(1-10)", "range(1, 10)", "[1 to 10]"], a: 0, exp: "<code>..</code> は範囲演算子です。" },

// --- 演算子と制御構文 (21-30) ---
{ q: "「数値」として等しいかを比較する演算子は?", o: ["==", "eq", "=", "==="], a: 0, exp: "数値比較は <code>==</code> です。<code>=</code> は代入です。" },
{ q: "「文字列」として等しいかを比較する演算子は?", o: ["eq", "==", "equals", "streq"], a: 0, exp: "文字列比較には <code>eq</code> (equal) を使います。<code>==</code> を使うと意図しない動作になることがあります。" },
{ q: "「数値」として「より大きい」比較演算子は <code>></code> ですが、「文字列」として「より大きい(辞書順)」比較演算子は?", o: ["gt", "ge", "lg", ">>"], a: 0, exp: "Greater Than の略で <code>gt</code> を使います。" },
{ q: "<code>if</code> 文の逆(もし~でなければ)を表すPerlらしい制御構文は?", o: ["unless", "ifnot", "except", "until"], a: 0, exp: "<code>unless ($condition) { ... }</code> は「条件が偽のとき」に実行されます。" },
{ q: "<code>foreach</code> ループなどで、現在の繰り返しをスキップして次へ進む(continue相当)命令は?", o: ["next", "skip", "continue", "pass"], a: 0, exp: "<code>next</code> はループの先頭に戻ります。" },
{ q: "ループをその場で中断して抜ける(break相当)命令は?", o: ["last", "break", "exit", "stop"], a: 0, exp: "<code>last</code> はブロックを脱出します。" },
{ q: "Perlにおいて <code>0</code> や <code>'0'</code> は真偽値としてどう扱われる?", o: ["偽 (False)", "真 (True)", "エラー", "未定義"], a: 0, exp: "Perlでは <code>0</code>, <code>'0'</code>, <code>''</code> (空文字), <code>undef</code> が「偽」となり、それ以外は「真」です。" },
{ q: "変数が定義されているかどうか(undefでないか)を確認する関数は?", o: ["defined", "exists", "isset", "check"], a: 0, exp: "<code>defined($var)</code> は値が入っていれば真を返します。" },
{ q: "ハッシュに特定の「キー」が存在するかを確認する関数は?", o: ["exists", "defined", "has_key", "contains"], a: 0, exp: "<code>exists $hash{$key}</code> は値がundefであっても、キーさえあれば真を返します。" },
{ q: "論理演算子「AND」と「OR」を表す、優先順位が低い単語形式の演算子は?", o: ["and, or", "&&, ||", "&, |", "with, else"], a: 0, exp: "<code>&&</code>, <code>||</code> と似ていますが、優先順位が低いため <code>open ... or die ...</code> のような制御フローによく使われます。" },

// --- 正規表現と文字列操作 (31-40) ---
{ q: "変数 <code>$text</code> が正規表現 <code>/cat/</code> に「マッチするか」を判定する演算子は?", o: ["=~", "==", "~=", "match"], a: 0, exp: "<code>$text =~ /pattern/</code> でマッチングを行います。" },
{ q: "変数 <code>$text</code> が正規表現に「マッチしない」ことを判定する演算子は?", o: ["!~", "!=~", "not~", "<>"], a: 0, exp: "<code>$text !~ /pattern/</code> はマッチしなければ真になります。" },
{ q: "文字列の置換を行う演算子は?", o: ["s/old/new/", "tr/old/new/", "m/old/new/", "r/old/new/"], a: 0, exp: "Substitution(置換)の <code>s///</code> を使います。<code>s/cat/dog/</code> でcatをdogにします。" },
{ q: "正規表現で「数字1文字」を表すメタ文字は?", o: ["\\d", "\\w", "\\s", "\\n"], a: 0, exp: "Digitの略で <code>\\d</code> です。" },
{ q: "正規表現で「空白文字(スペース、タブ等)」を表すメタ文字は?", o: ["\\s", "\\w", "\\b", "\\t"], a: 0, exp: "Spaceの略で <code>\\s</code> です。" },
{ q: "行末の改行文字を取り除くための関数は?", o: ["chomp", "chop", "trim", "strip"], a: 0, exp: "<code>chomp($str)</code> は末尾の改行コードのみを安全に削除します。" },
{ q: "文字列を指定した区切り文字で分割して配列にする関数は?", o: ["split", "explode", "cut", "divide"], a: 0, exp: "<code>my @list = split(/,/, $csv);</code> のように使います。" },
{ q: "配列の要素を指定した文字で連結して1つの文字列にする関数は?", o: ["join", "implode", "concat", "merge"], a: 0, exp: "<code>my $str = join('-', @list);</code> のように使います。" },
{ q: "文字列の長さ(文字数)を返す関数は?", o: ["length", "size", "count", "len"], a: 0, exp: "<code>length($str)</code> を使います。" },
{ q: "大文字・小文字を区別せずにマッチさせるための正規表現修飾子は?", o: ["/i", "/g", "/m", "/s"], a: 0, exp: "Insensitiveの <code>/i</code> を使い、<code>/pattern/i</code> と書きます。" },

// --- サブルーチンとその他 (41-50) ---
{ q: "サブルーチン(ユーザー定義関数)を定義するキーワードは?", o: ["sub", "function", "def", "func"], a: 0, exp: "<code>sub my_func { ... }</code> と書きます。" },
{ q: "サブルーチン内で、渡された引数が格納されている特殊配列は?", o: ["@_", "$ARGV", "@ARGS", "$_"], a: 0, exp: "引数は <code>@_</code> に入っており、<code>my ($a, $b) = @_;</code> のように受け取ります。" },
{ q: "サブルーチンから値を戻すためのキーワードは?", o: ["return", "result", "back", "yield"], a: 0, exp: "<code>return $value;</code> で値を返します。省略すると最後の式の値が返ります。" },
{ q: "多くのループや関数で、引数を省略した時に使われる「デフォルト変数」は?", o: ["$_", "$0", "$@", "$!"], a: 0, exp: "<code>$_</code> はPerlの代名詞的存在で、明示しない場合の操作対象になります。" },
{ q: "ファイルを開くための関数は?", o: ["open", "read", "file", "connect"], a: 0, exp: "<code>open(my $fh, '<', 'file.txt')</code> のように使います。" },
{ q: "ファイルを開くのに失敗した時、エラーメッセージを表示して終了する定型句は?", o: ["or die", "or exit", "catch error", "on error"], a: 0, exp: "<code>open ... or die \"Error: $!\";</code> が伝統的なイディオムです。" },
{ q: "コマンドライン引数が格納されている特殊配列は?", o: ["@ARGV", "@_", "$ARGS", "%ENV"], a: 0, exp: "スクリプト実行時に渡された引数は <code>@ARGV</code> に入ります。" },
{ q: "環境変数が格納されている特殊ハッシュは?", o: ["%ENV", "%ARGV", "$ENV", "@ENV"], a: 0, exp: "<code>$ENV{PATH}</code> のようにアクセスします。" },
{ q: "OSのエラーメッセージ(No such file or directoryなど)が格納される特殊変数は?", o: ["$!", "$@", "$?", "$_"], a: 0, exp: "システムコール失敗時のエラーは <code>$!</code> (errno) に入ります。" },
{ q: "モダンなPerl(5.10以降)で、改行付きで出力する <code>print</code> のような機能を使うための宣言は?", o: ["use feature 'say';", "use Say;", "require 5.10;", "include say;"], a: 0, exp: "<code>use feature 'say';</code> を書くと、末尾に改行を自動でつける <code>say</code> 関数が使えます。" }
];

// 初期化
function init() {
els.mainTitle.textContent = CONFIG.title;
state.questions = ALL_QUESTIONS;

// シャッフルして出題
shuffleArray(state.questions);

state.currentIndex = 0;
state.score = 0;
state.userAnswers = [];

els.quizArea.classList.remove('hidden');
els.resultArea.classList.add('hidden');

showQuestion();
}

// 問題表示
function showQuestion() {
if (state.currentIndex >= state.questions.length) {
endQuiz();
return;
}

// UIリセット
els.feedbackArea.classList.add('hidden');
els.timerArea.style.display = 'block';
els.options.innerHTML = '';
els.nextBtn.style.display = 'none';

// プログレスバー更新
const progress = ((state.currentIndex) / state.questions.length) * 100;
els.progressFill.style.width = `${progress}%`;

const qData = state.questions[state.currentIndex];
els.qNum.textContent = `QUESTION ${state.currentIndex + 1} / ${state.questions.length}`;
els.qText.innerHTML = qData.q;

// 選択肢生成
const opts = qData.o.map((text, i) => ({ text, isCorrect: i === qData.a }));
shuffleArray(opts);

opts.forEach(opt => {
const btn = document.createElement('button');
btn.className = 'option';
btn.innerHTML = opt.text;
btn.onclick = () => handleAnswer(opt.isCorrect, btn);
btn.dataset.correct = opt.isCorrect;
els.options.appendChild(btn);
});

startTimer();
}

// タイマー開始
function startTimer() {
clearInterval(state.timer);
state.timeLeft = CONFIG.timerSeconds;
els.timer.textContent = state.timeLeft;

state.timer = setInterval(() => {
state.timeLeft--;
els.timer.textContent = state.timeLeft;
if (state.timeLeft <= 0) {
clearInterval(state.timer);
handleAnswer(false, null, true); // 時間切れ
}
}, 1000);
}

// 回答処理
function handleAnswer(isCorrect, btnElement, isTimeout = false) {
clearInterval(state.timer);

// 全ボタン無効化 & 正解表示
const buttons = els.options.querySelectorAll('.option');
buttons.forEach(b => {
b.disabled = true;
if (b.dataset.correct === "true") {
b.classList.add('correct-answer');
}
});

if (isTimeout) {
els.fbTitle.textContent = "時間切れ...";
els.fbTitle.className = "fb-incorrect";
} else {
if (isCorrect) {
btnElement.classList.add('correct-choice');
state.score++;
els.fbTitle.textContent = "正解!";
els.fbTitle.className = "fb-correct";
} else {
btnElement.classList.add('incorrect-choice');
els.fbTitle.textContent = "不正解...";
els.fbTitle.className = "fb-incorrect";
}
}

// 履歴保存
const qData = state.questions[state.currentIndex];
state.userAnswers.push({
q: qData.q,
a: qData.o[qData.a],
isCorrect: isCorrect,
userChoice: isTimeout ? "時間切れ" : btnElement.textContent
});

// 解説表示
els.fbText.innerHTML = qData.exp;
els.feedbackArea.classList.remove('hidden');
els.timerArea.style.display = 'none';

// 次へボタン
els.nextBtn.style.display = 'block';
els.nextBtn.onclick = () => {
state.currentIndex++;
showQuestion();
};
}

// 終了処理
function endQuiz() {
els.quizArea.classList.add('hidden');
els.resultArea.classList.remove('hidden');

const percentage = Math.round((state.score / state.questions.length) * 100);
els.scoreDisplay.textContent = `${state.score} / ${state.questions.length} (${percentage}%)`;

let msg = "";
if (percentage === 100) msg = "完璧です!Perlの基礎は完全にマスターしています。";
else if (percentage >= 80) msg = "素晴らしい成績です!自信を持ってコードを書きましょう。";
else if (percentage >= 60) msg = "合格点です!基本は理解できています。";
else msg = "まずは基本をしっかり復習しましょう。繰り返しが大切です。";

els.resultMsg.textContent = msg;

// 詳細レビュー生成
els.reviewList.innerHTML = "";
state.userAnswers.forEach((ans, i) => {
const div = document.createElement('div');
div.className = "review-item";
const statusClass = ans.isCorrect ? "ok" : "ng";
const statusIcon = ans.isCorrect ? "✔" : "✘";
div.innerHTML = `
<div class="review-q"><span class="review-status ${statusClass}">${statusIcon} Q${i+1}</span>: ${ans.q}</div>
<div class="review-ans">正解: <b>${ans.a}</b></div>
`;
els.reviewList.appendChild(div);
});
}

// ユーティリティ
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}

// イベントリスナー
els.restartBtn.addEventListener('click', init);

// 開始
init();

</script>
</body>
</html>


使用変数

$str
$text
, "def", "func"], a: 0, exp: "<code>sub my_func { ... }</code> と書きます。" }, { q: "サブルーチン内で、渡された引数が格納されている特殊配列は?", o: ["@_", "$ARGV", "@ARGS", "$_"], a: 0, exp: "引数は <code>@_</code> に入っており、<code>my -------( Function )
@list
ALL_QUESTIONS
b
btn
buttons
charset
class
className
CONFIG
content
correct
currentIndex
disabled
display
div
els
endQuiz -------( Function )
handleAnswer -------( Function )
i
id
init -------( Function )
innerHTML
isTimeout
j
key
lang
msg
name
onclick
opt
opts
percentage
progress
qData
questions
scale
score
showQuestion -------( Function )
shuffleArray -------( Function )
startTimer -------( Function )
state
statusClass
statusIcon
textContent
timeLeft
timer
userAnswers
width
~