素人なりに本気でJavaScriptでクイズアプリを作ってみた。

どうも。

JavaScriptでクイズアプリを作ってみました。

こちら[おいしい数学](https://hiraocafe.com)という現在月間40万PVぐらいのサイトを運営しているものです。ネットだとAKRという名前を使っている場合もあります。別に本名を隠したいとかまったくないのですが。

さて、受験生が入試前に、数学(今回はIA)の頻出事項、弱い事項が確認できるように、クイズアプリを作りたいと思いました。

完成はこちらです→[ファイナルチェック数学IA](https://hiraocafe.com/note/finalcheck1a.html)

条件としては
・答えを場所で覚えないため選択肢がランダムで表示されて欲しい
・数式も問題なく表示して欲しい
・得点を集計し、それに応じた判定文を出す。そして解けなかった問題を最後に提示する

この辺です。

htmlとJavaScriptのソースコードを公開します。このアプトプットが将来の自分、そしてどなたか(特にプログラミング経験が浅い人)のためになれば幸いです。

まずはhtmlから(articleタグの中だけ公開です)

```html:finalcheck1a.html
<article>
   <h1>ファイナルチェック数学IA</h1>
   <div id="front" style="display: block">
       <div class="waku">
           <p id="js-number" style="text-align: center"></p>
           <div id="js-question">
                        質問入ります．
           </div>
       </div>
       <div id="buttons">
           <button type="button" class="btn" style="width: 100%">選択肢1</button>
           <button type="button" class="btn" style="width: 100%">選択肢2</button>
           <button type="button" class="btn" style="width: 100%">選択肢3</button>
           <button type="button" class="btn" style="width: 100%">選択肢4</button>
           <button type="button" class="btn" style="width: 100%">選択肢5</button>
       </div>
   </div>
   <div id="nextbtnarea" style="text-align: center; display: none">
       <div class="nextbtn">次の問題へ</div>
       <div class="waku2">
           <p><span class="wakumei">解答</span></p>
           <div id="commentarea" style="text-align:left"></div>
       </div>
       <div class="nextbtn">次の問題へ</div>
   </div>
   <div id=kekka class="waku2" style="display: none">
       <p style="text-align: center"><span class="wakumei">診断結果</span></p>
       <div id="result"></div>
       <div style="text-align: center">
           <a class="share-7" id="getResult">
               <i class="fab fa-twitter">結果をツイートする</i>
           </a>
       </div>
       <br>
   </div>
   <div class="returnbox">
       <p><a href="finalcheck1a.html">ファイナルチェック数学IATopへ</a></p>
   </div>
</article>
```

構造として大きく分けて、
front
nextbtnarea
kekka
というdivタグのidに分かれています。これらをdisplayでblockとnoneを状況に応じて切り替えることで、クイズの進行を行います。

frontは問題文と選択肢のボタン、nextbtnareaは次へボタンと解答が表示されます。
kekkaは正解数と判定文、間違えたテーマを表示します。問題がすべて終わったらdisplay: blockすればOKです。

さてさて、JavaScriptをすべて表示します。演出に[sweetalert2](https://sweetalert2.github.io)を使っているので意味わからん記述があれば多分それです。

```javascript:finalcheck1a.js
let result =document.getElementById('result');
let nextbtn =document.getElementsByClassName('nextbtn');

// 問題と選択肢と解答のセット．answersの一番上に解答を置く．
const quiz = [
    {
        question: '<p>すべての実数 $A$ に関して $\\sqrt{A^{2}}=$ □ が成り立つ．□に入る適切なものを答えよ．</p>',
        answers: [
            '$|A|$',
            '$A$',
            '$\\pm A$',
            '$-A$',
            'わからない',
        ],
        comment: '<p>$\\sqrt{A^{2}}=\\boldsymbol{|A|}$</p><p style=\"font-size: small\">テーマ：<a href=\"zettaichi.html\" target=\"_blank\">絶対値と $\\sqrt{A^2}$ の外し方</a></p>',
    },
    {
        question: '<p>$2$ つの三角形の面積が等しいことは，$2$ つの三角形が合同であるための□．□に適切なものを答えよ．</p>',
        answers: [
            '必要条件であるが十分条件でない．',
            '十分条件であるが必要条件でない．',
            '必要十分条件である．',
            '必要条件でも十分条件でもない．',
            'わからない',
        ],
        comment: '<p>$p$：$2$ つの三角形の面積が等しい</p><p>$q$：$2$ つの三角形が合同</p><p>とすると，$p \\Longleftarrow q$ であるので，$p$ は $q$ であるための<b>必要条件であるが十分条件でない．</b></p><p style=\"font-size: small\">テーマ：<a href=\"necessary_sufficient_condition.html\" target=\"_blank\">必要条件，十分条件の問題の解き方</a></p>',
    },
    {
        question: '<p>$n$ を整数とする．「 $n^{2}+4n+1$ が奇数ならば $n$ が奇数．」この命題の対偶と，その真偽の組を答えよ．</p>',
        answers: [
            '「 $n$ が偶数ならば $n^{2}+4n+1$ が偶数．」，偽',
            '「 $n$ が偶数ならば $n^{2}+4n+1$ が偶数．」，真',
            '「 $n$ が奇数ならば $n^{2}+4n+1$ が奇数．」，真',
            '「 $n$ が奇数ならば $n^{2}+4n+1$ が奇数．」，偽',
            'わからない',
        ],
        comment: '<p>「 $n^{2}+4n+1$ が奇数ならば $n$ が奇数．」の対偶は<b>「 $\\boldsymbol{n}$ が偶数ならば $\\boldsymbol{n^{2}+4n+1}$ が偶数．」</b></p><p>$n=2k$ ( $k$ は整数)とすると</p><p>$n^{2}+4n+1=2(2k^{2}+4k)+1$ となり，$n^{2}+4n+1$ は奇数となるから<b>偽</b>．</p><p style=\"font-size: small\">テーマ：逆，裏，対偶</p>',
    },
    {
        question: '<p>$a$ を定数とする．$2$ 次関数 $y=x^{2}-2ax+2a^{2}$ $(0\\leqq x \\leqq 2)$ の $0 &lt; a &lt; 1$ のときの最大値 $M$ と最小値 $m$ の組を選べ．</p>',
        answers: [
            '$M=2a^{2}-4a+4$，$m=a^{2}$',
            '$M=2a^{2}$，$m=a^{2}$',
            '$M=2a^{2}-4a+4$，$m=2a^{2}$',
            '$M=2a^{2}$，$m=2a^{2}-2a+1$',
            'わからない',
        ],
        comment: '<p>$y=(x-a)^{2}+a^{2}$ $(0\\leqq x \\leqq 2)$ において，$0 &lt; a &lt; 1$ のとき図は以下のようになる．</p><div style=\"text-align: center\"><img src=\"noteimages/finalcheck1a1.png\" alt=\"問題4の図\" width=\"100%\"></div><p>$x=2$ のとき最大値 $\\boldsymbol{M=2a^{2}-4a+4}$</p><p>$x=a$ のとき最小値 $\\boldsymbol{m=a^{2}}$</p><p style=\"font-size: small\">テーマ：<a href=\"2jikansumaxmin-jikumove.html\" target=\"_blank\">2次関数の最大最小(グラフ変動，定義域固定)</a></p>',
    },
    {
        question: '<p>$2$ 次関数 $y=x^{2}-2mx-m+2$ のグラフと $x$ 軸の正の部分が異なる $2$ 点で交わるように，定数 $m$ の値の範囲を定めよ．</p>',
        answers: [
            '$1 &lt; m &lt; 2$',
            '$m &lt; 2$',
            '$m &lt; -2$，$1 &lt; m$',
            '$1 &lt; m$',
            'わからない',
        ],
        comment: '<div style=\"text-align: center\"><img src=\"noteimages/finalcheck1a2.png\" alt=\"問題5の図\" width=\"100%\"></div><p>$x=0$ のとき $y=-m+2&gt;0$ より $m&lt;2$</p><p>軸に関して $m&gt;0$</p><p>異なる $2$ つの実数解をもつので，$\\dfrac{D}{4}=m^{2}+m-2&gt;0$ より $m&lt;-2$，$1&lt;m$</p><p>これらの共通範囲より $\\boldsymbol{1&lt;m &lt;2}$</p><p style=\"font-size: small\">テーマ：<a href=\"kainohaichi.html\" target=\"_blank\">2次方程式の解の配置問題</a></p>',
    },
    {
        question: '<p>辺の長さが $4$，$5$，$6$ の三角形の面積 $S$ と，外接円の半径 $R$，内接円の半径 $r$ の組を選べ．</p>',
        answers: [
            '$S=\\dfrac{15\\sqrt{7}}{4}$，$R=\\dfrac{8\\sqrt{7}}{7}$，$r=\\dfrac{\\sqrt{7}}{2}$',
            '$S=\\dfrac{15\\sqrt{7}}{4}$，$R=\\dfrac{4\\sqrt{7}}{7}$，$r=\\dfrac{\\sqrt{7}}{2}$',
            '$S=\\dfrac{15\\sqrt{7}}{4}$，$R=\\dfrac{8\\sqrt{7}}{7}$，$r=\\sqrt{7}$',
            '$S=\\dfrac{5}{4}$，$R=\\dfrac{4\\sqrt{7}}{7}$，$r=\\dfrac{1}{6}$',
            'わからない',
        ],
        comment: '<div style=\"text-align: center\"><img src=\"noteimages/3-edges-area1.png\" alt=\"問題７の図\" width=\"100%\"></div><p>図のように $\\theta$ を設定すると，<a href=\"law-of-cosines.html\" target=\"_blank\">余弦定理</a>より</p><p style=\"text-align: center\">$\\cos\\theta=\\dfrac{4^{2}+5^{2}-6^{2}}{2\\cdot4\\cdot5}=\\dfrac{1}{8}$</p><p style=\"text-align: center\">$\\sin^{2}\\theta=1-\\cos^{2}\\theta=\\dfrac{63}{64}$</p><p>$\\sin\\theta&gt;0$ より</p><p style=\"text-align: center\">$\\sin\\theta=\\dfrac{3\\sqrt{7}}{8}$</p><p style=\"text-align: center\">$\\therefore \\ S=\\dfrac{1}{2}\\cdot4\\cdot5\\sin \\theta=\\boldsymbol{\\dfrac{15\\sqrt{7}}{4}}$</p><p><a href=\"law-of-sines.html\" target=\"_blank\">正弦定理</a>より</p><p style=\"text-align: center\">$\\dfrac{6}{\\sin \\theta}=2R$</p><p style=\"text-align: center\">$\\therefore \\ R=\\boldsymbol{\\dfrac{8\\sqrt{7}}{7}}$</p><p>三角形の面積に関して</p><p style=\"text-align: center\">$\\dfrac{15\\sqrt{7}}{4}=\\dfrac{r}{2}(4+5+6)$</p><p style=\"text-align: center\">$\\therefore \\ r=\\boldsymbol{\\dfrac{\\sqrt{7}}{2}}$</p><p style=\"font-size: small\">テーマ：<a href=\"3-edges-area.html\" target=\"_blank\">3辺既知の三角形の面積の出し方</a>，三角形の面積と内接円の半径</p>',
    },
    {
        question: '<p>次に $10$ 点満点の数学の小テストのデータがある．中央値 $a$ と四分位偏差 $b$ の正しい組を選べ．</p><p style="text-align: center">$5$，$5$，$5$，$7$，$10$，$10$</p>',
        answers: [
            '$a=6$，$b=\\dfrac{5}{2}$',
            '$a=6$，$b=5$',
            '$a=7$，$b=\\dfrac{5}{2}$',
            '$a=7$，$b=5$',
            'わからない',
        ],
        comment: '<p>下位のデータ $5$，$5$，$5$ であり，上位のデータは $7$，$10$，$10$ である．中央値 $a=\\dfrac{5+7}{2}=\\boldsymbol{6}$．第一四分位数 $Q_{1}=5$，第三四分位数 $Q_{3}=10$ より，四分位偏差 $b=\\dfrac{Q_{3}-Q_{1}}{2}=\\boldsymbol{\\dfrac{5}{2}}$</p>',
    },
    {
        question: '<p>次のデータはある1月の豚汁屋で，その日の最高気温 $x$ (℃) とその日に売れた豚汁の販売数 $y$ (本) の表である．4日間をデータにまとめた．</p><table border="1px\" cellpadding=\"10px\" style=\"border-collapse: collapse\" align=\"center\"><caption></caption><tr><td>曜日</td><td>1日目</td><td>2日目</td><td>3日目</td><td>4日目</td></tr><tr><th>$x$</th><th>$1$</th><th>$1$</th><th>$0$</th><th>$4$</th></tr><tr><th>$y$</th><th>$7$</th><th>$6$</th><th>$10$</th><th>$5$</th></tr></table><p>$x$，$y$ のデータの相関係数 $r$ の値を求めよ．</p>',
        answers: [
            '$-\\dfrac{3\\sqrt{14}}{14}$',
            '$-\\dfrac{2}{7}$',
            '$-\\dfrac{3\\sqrt{42}}{28}$',
            '$\\dfrac{2\\sqrt{14}}{7}$',
            'わからない',
        ],
        comment: '<p>$\\overline{x}=\\dfrac{1+1+0+4}{4}=\\dfrac{3}{2}$</p><p>$\\overline{y}=\\dfrac{7+6+10+5}{4}=7$</p><p>分散に関しては $s_{x}^{2}$ は $\\overline{x}$ が分数かつデータが $0$ に近いので $s_{x}^{2}=\\overline{x^2}-(\\overline{x})^{2}$ で求めると楽です．$s_{y}^{2}$ は $\\overline{y}$ が自然数なので定義通り求めるのが計算しやすいと思います．</p><p>$s_{x}^{2}=\\overline{x^2}-(\\overline{x})^{2}=\\dfrac{1^{2}+1^{2}+0^{2}+4^{2}}{4}-\\left(\\dfrac{3}{2}\\right)^{2}=\\dfrac{9}{4}$</p><p>$s_{y}^{2}=\\dfrac{0^{2}+(-1)^{2}+3^{2}+(-2)^{2}}{4}=\\dfrac{14}{4}$</p><p>$s_{xy}=\\dfrac{0+\\dfrac{1}{2}+\\dfrac{-9}{2}+\\dfrac{-10}{2}}{4}=-\\dfrac{9}{4}$</p><p>$r=\\dfrac{s_{xy}}{s_{x}s_{y}}=-\\dfrac{9}{4}\\cdot \\dfrac{2}{3}\\cdot \\dfrac{2}{\\sqrt{14}}=\\boldsymbol{-\\dfrac{3\\sqrt{14}}{14}}$</p><p style=\"font-size: small\">※ $s_{xy}=\\overline{xy}-\\overline{x}\\cdot\\overline{y}=\\dfrac{7+6+0+20}{4}-\\dfrac{3}{2}\\cdot7=-\\dfrac{9}{4}$ として出す方が速いでしょうか．</p><p style=\"font-size: small\">テーマ：相関係数の出し方．<a href=\"kyoubunsan.html\" target=\"_blank\">共分散のもう一つの出し方</a></p>',
    },
    {
        question: '<p>変量 $x$ のデータを $y=2x+10$ の式で変量 $y$ のデータを得る．変量 $y$ の平均 $\\overline{y}$ と分散 $s_{y}^{2}$ の正しい組を選べ．</p>',
        answers: [
            '$\\overline{y}=2\\overline{x}+10$，$s_{y}^{2}=4s_{x}^{2}$ ',
            '$\\overline{y}=2\\overline{x}$，$s_{y}^{2}=4s_{x}^{2}$ ',
            '$\\overline{y}=2\\overline{x}+10$，$s_{y}^{2}=2s_{x}^{2}$ ',
            '$\\overline{y}=2\\overline{x}+10$，$s_{y}^{2}=2s_{x}^{2}+10$ ',
            'わからない',
        ],
        comment: '<p>変量 $x$ の値を $x_{i}$ ( $i=1,2,\\cdots,n$ )とする．変量 $y$ のデータは $y_{i}=2x_{i}+10$ ( $i=1,2,\\cdots,n$ )となる．</p><p><a href=\"sigmaformula.html\" target=\"_blank\">シグマ記号</a>を使います．</p><p>　$\\overline{y}$</p><p>$\\displaystyle =\\dfrac{1}{n}\\sum_{k=1}^{n}y_{k}$</p><p>$\\displaystyle =\\dfrac{1}{n}\\sum_{k=1}^{n}(2x_{k}+10)$</p><p>$\\displaystyle =2\\cdot\\dfrac{1}{n}\\sum_{k=1}^{n}x_{k}+\\dfrac{1}{n}\\cdot 10n$</p><p>$\\displaystyle =\\boldsymbol{2\\overline{x}+10}$</p><p>　$s_{y}^{2}$</p><p>$\\displaystyle =\\dfrac{1}{n}\\sum_{k=1}^{n}(y_{k}-\\overline{y})^{2}$</p><p>$\\displaystyle =\\dfrac{1}{n}\\sum_{k=1}^{n}(2x_{k}+10-2\\overline{x}-10)^{2}$</p><p>$\\displaystyle =\\dfrac{1}{n}\\sum_{k=1}^{n}(2x_{k}-2\\overline{x})^{2}$</p><p>$\\displaystyle =4\\cdot\\dfrac{1}{n}\\sum_{k=1}^{n}(x_{k}-\\overline{x})^{2}$</p><p>$\\displaystyle =\\boldsymbol{4s_{x}^{2}}$</p><p style=\"font-size: small\">テーマ：変量の変換をした平均と分散</p>',
    },
    {
        question: '<p>R，I，N，G，Oの5文字を1列に並べるとき，R，N，Gがこの順に並ぶものは何通りか．</p>',
        answers: [
            '$20$ 通り',
            '$40$ 通り',
            '$120$ 通り',
            '$60$ 通り',
            'わからない',
        ],
        comment: '<p>R，N，Gを□として1列に並べるのは $\\dfrac{5!}{3!}$ 通り．並べた後の□にR，N，Gをこの順に配置するのは $1$ 通り</p><p>　$\\dfrac{5!}{3!}\\cdot 1=\\boldsymbol{20}$ 通り</p><p style=\"font-size: small\">テーマ：<a href=\"order-permutation.html\" target=\"_blank\">順序が定まった順列</a></p>',
    },
    {
        question: '<p>$6$ 個の異なる玉を次のように分けるのは何通りか．</p><p>(1) $3$ 個，$2$ 個，$1$ 個の $3$ 組に分ける方法．</p><p>(2) $2$ 個，$2$ 個，$2$ 個の $3$ 組に分ける方法．</p>',
        answers: [
            '(1) $60$ 通り　(2) $15$ 通り',
            '(1) $60$ 通り　(2) $30$ 通り',
            '(1) $10$ 通り　(2) $5$ 通り',
            '(1) $20$ 通り　(2) $15$ 通り',
            'わからない',
        ],
        comment: '<p>(1) 順に $1$ 個，$2$ 個，$3$ 個と配ると</p><p>　$_{6}{\\rm C}_{1}\\cdot _{5}\\hspace{-1.3mm}{\\rm C}_{2}\\cdot 1=\\boldsymbol{60}$ 通り</p><p>(2) 順に $2$ 個，$2$ 個，$2$ 個と配るが，$2$ 個のグループ $3$ つは区別がつかない．</p><p>　$_{6}{\\rm C}_{2}\\cdot _{4}\\hspace{-1.3mm}{\\rm C}_{2}\\cdot 1\\div 3!=\\boldsymbol{15}$ 通り</p><p style=\"font-size: small\">テーマ：<a href=\"kumiwake.html\" target=\"_blank\">組分け問題</a></p>',
    },
    {
        question: '<p>(1) $1\\leqq x &lt; y&lt; z\\leqq 5$ を満たす整数の組 $(x,y,z)$ は何通りか．</p><p>(2) $1\\leqq x \\leqq y \\leqq z \\leqq 5$ を満たす整数の組 $(x,y,z)$ は何通りか．</p>',
        answers: [
            '(1) $10$ 通り　(2) $35$ 通り',
            '(1) $35$ 通り　(2) $120$ 通り',
            '(1) $10$ 通り　(2) $120$ 通り',
            '(1) $10$ 通り　(2) $24$ 通り',
            'わからない',
        ],
        comment: '<p>(1) $1$ から $5$ までの中から $3$ 個選び，小さい順に $x$，$y$，$z$ と対応させるのは $1$ 通り</p><p>　$_{5}{\\rm C}_{3}\\cdot 1=\\boldsymbol{10}$ 通り</p><p>(2) $1$ から $5$ までの $5$ つの部屋に，$3$ 個の区別がつかないボールを配ると考える．仕切り $4$ 本，ボール $3$ 個の同じものを含む順列より $\\dfrac{7!}{4!3!}$ 通り．ボールの行き先の部屋と $x$，$y$，$z$ を対応させるのは $1$ 通り</p><p>　$\\dfrac{7!}{4!3!}\\cdot 1=\\boldsymbol{35}$ 通り</p><p style=\"font-size: small\">テーマ：不等式を満たす場合の数</p>',
    },
    {
        question: '<p>サイコロを $4$ 回投げる．次の確率を求めよ．</p><p>(1) $3$ 回偶数が出て，$1$ 回奇数が出る．</p><p>(2) $2$ 回 $1$ の目が出て，$1$ 回素数が出て，$1$ 回 $4$ または $6$ の目が出る．</p>',
        answers: [
            '(1) $\\dfrac{1}{4}$　(2) $\\dfrac{1}{18}$',
            '(1) $\\dfrac{1}{4}$　(2) $\\dfrac{1}{9}$',
            '(1) $\\dfrac{1}{16}$　(2) $\\dfrac{1}{9}$',
            '(1) $\\dfrac{1}{16}$　(2) $\\dfrac{1}{18}$',
            'わからない',
        ],
        comment: '<p>(1) $_{4}{\\rm C}_{3}\\left(\\dfrac{1}{2}\\right)^{3}\\dfrac{1}{2}=\\boldsymbol{\\dfrac{1}{4}}$</p><p>(2) $\\dfrac{4!}{2!1!1!}\\left(\\dfrac{1}{6}\\right)^{2}\\dfrac{1}{2}\\cdot\\dfrac{1}{3}=\\boldsymbol{\\dfrac{1}{18}}$</p><p style=\"font-size: small\">テーマ：反復試行の確率</p>',
    },
    {
        question: '<p>ある病気には $10$ %の確率でかかってしまう．ある検査では $90$ %の確率で正しい判定をし，$10$ %の確率で誤った判定をする．A君がある検査で陽性と出た，A君が実際に病気にかかっている確率はいくつか．</p>',
        answers: [
            '$\\dfrac{1}{2}$',
            '$\\dfrac{9}{10}$',
            '$\\dfrac{81}{100}$',
            '$\\dfrac{1}{10}$',
            'わからない',
        ],
        comment: '<p>　$P_{陽性}(病気)$</p><p>$=\\dfrac{P(陽性 \\cap 病気)}{P(陽性)}$</p><p>$=\\dfrac{P(病気 \\cap 陽性)}{P(病気 \\cap 陽性)+P(平気 \\cap 陽性)}$</p><p>$=\\dfrac{0.1\\times 0.9}{0.1\\times 0.9+0.9\\times 0.1}$</p><p>$=\\boldsymbol{\\dfrac{1}{2}}$</p><p style=\"font-size: small\">テーマ：条件付き確率</p>',
    },
    {
        question: '<p>三角形の外心，内心，重心の定義の組み合わせとして適切なものはどれか．</p>',
        answers: [
            '外心：各辺の垂直二等分線の交点<br>内心：各内角の二等分線の交点<br>重心：各中線の交点',
            '外心：各内角の二等分線の交点<br>内心：各辺の垂直二等分線の交点<br>重心：各中線の交点',
            '外心：各辺の垂直二等分線の交点<br>内心：各中線の交点<br>重心：各内角の二等分線の交点',
            '外心：各垂線の交点<br>内心：各内角の二等分線の交点<br>重心：各中線の交点．',
            'わからない',
        ],
        comment: '<p><b>外心：各辺の垂直二等分線の交点<br>内心：各内角の二等分線の交点<br>重心：各中線の交点</b></p>',
    },
    {
        question: '<p>すべての面が四角形となっている凸多面体 $P$ がある．$P$ の面の数が $29$ のとき，$P$ の辺の数と頂点の数の組み合わせとして正しいものはどれか．</p>',
        answers: [
            '辺：$58$　頂点：$31$',
            '辺：$116$　頂点：$89$',
            '辺：$58$　頂点：$58$',
            '辺：$29$　頂点：$58$',
            'わからない',
        ],
        comment: '<p>辺の数を $e$，頂点の数を $v$ とする．</p><p>すべて面をバラバラにすると辺の数は $29\\times4=116$ 本だが，立体にすると $2$ つの辺が対応して $1$ つの辺になるので $e=116\\div2=\\boldsymbol{58}$</p><p>オイラーの多面体定理より</p><p style=\"text-align: center\">$v-58+29=2$　$\\therefore v=\\boldsymbol{31}$</p><p style=\"font-size: small\">テーマ：オイラーの多面体定理</p>',
    },
    {
        question: '<p>$2022$ の正の約数の個数とその総和の組み合わせとして正しいものはどれか．ちなみに $2022=2\\cdot3\\cdot337$ と素因数分解できる．</p>',
        answers: [
            '個数：$8$　総和：$4056$',
            '個数：$8$　総和：$4057$',
            '個数：$8$　総和：$2033$',
            '個数：$6$　総和：$2033$',
            'わからない',
        ],
        comment: '<p>$2022$ の正の約数は $2^{x}3^{y}337^{z}$ ( $x,y,z$ は $0$ または $1$ )と表せるので個数は $2\\cdot2\\cdot2=\\boldsymbol{8}$ 個．</p><p>約数の総和は $(1+2)(1+3)(1+337)=\\boldsymbol{4056}$</p><p style=\"font-size: small\">テーマ：正の約数の個数と総和</p>',
    },
    {
        question: '<p>$133x-30y=1$ を満たす整数解をすべて求めよ．</p>',
        answers: [
            '$x=30k+7，y=133k+31$ ( $k$ は整数)',
            '$x=30k+7，y=-133k+31$ ( $k$ は整数)',
            '$x=30k+17，y=133k+75$ ( $k$ は整数)',
            '$x=30k+17，y=-133k+75$ ( $k$ は整数)',
            'わからない',
        ],
        comment: '<div style=\"text-align: center\"><img src=\"noteimages/finalcheck1a3.png\" alt=\"ユークリッドの互除法\" width=\"100%\"></div><p><p>$\\begin{align}1&=13-4\\times 3 \\\\ & =13-(30-13\\times2)\\times3 \\\\ & =13\\times7-30\\times3 \\\\ & =(133-30\\times4)\\times7-30\\times3 \\\\ & =133\\times7-30\\times31\\end{align}$</p></p><p>　　　$133x-30y=1$</p><p>　$\\underline{- \\ ) \\ \\ 133\\cdot7-30\\cdot31=1 \\ \\hspace{11mm} \\ }$</p><p>　$133(x-7)-30(y-31)=0$</p><p>$\\Longleftrightarrow \\ 133(x-7)=30(y-31)$</p><p>　$\\therefore \\ \\begin{cases} x-7=30k \\\\ y-31=133k \\end{cases}$　( $k$ は整数)</p><p>$\\boldsymbol{x=30k+7，y=133k+31}$ <b>( $\\boldsymbol{k}$ は整数)</b></p><p style=\"font-size: small\">テーマ：<a href=\"euclidtokushukai.html\" target=\"_blank\">ユークリッドの互除法による特殊解の求め方</a></p>',
    },
]

const quizLength = quiz.length;
let quizIndex = 0;

let score = 0;

const $button = document.getElementsByTagName('button');
const buttonLength = $button.length;

let rand0 = Math.floor(Math.random() * (buttonLength-1));
let rand1 = Math.floor(Math.random() * (buttonLength-1));
let rand2 = Math.floor(Math.random() * (buttonLength-1));
let rand3 = Math.floor(Math.random() * (buttonLength-1));
let randbox = [rand0,rand1,rand2,rand3];

//クイズの問題文，選択肢を決定する関数．選択肢はランダムで決まる．
const setupQuiz = () => {
    document.getElementById('js-number').innerHTML = '<p style="color: darkblue"><b>問題 ' + (quizIndex+1)  + ' (全' + (quizLength)  + '問)</b></p>';
    document.getElementById('js-question').innerHTML = quiz[quizIndex].question;
    document.getElementById('commentarea').innerHTML = quiz[quizIndex].comment;
    
    //2回目以降のクイズで前回の配置をリセットするために必要
    rand0 = Math.floor(Math.random() * (buttonLength-1));
    rand1 = Math.floor(Math.random() * (buttonLength-1));
    rand2 = Math.floor(Math.random() * (buttonLength-1));
    rand3 = Math.floor(Math.random() * (buttonLength-1));
    
    while (rand0 == rand1) {
        rand1 = Math.floor(Math.random() * (buttonLength-1));
    }
    
    while (rand0 == rand2 || rand1 == rand2) {
        rand2 = Math.floor(Math.random() * (buttonLength-1));
    }
    
    while (rand0 == rand3 || rand1 == rand3 || rand2 == rand3) {
        rand3 = Math.floor(Math.random() * (buttonLength-1));
    }
    
    randbox = [rand0,rand1,rand2,rand3];
    
    //0,1,2,3ボタンに選択肢を配置
    for(let i = 0; i < 4; i++){
        $button[i].innerHTML = quiz[quizIndex].answers[randbox[i]];
    }
    //5番目のボタンだけ必ずわからないにする
    $button[4].innerHTML = quiz[quizIndex].answers[4];
}

//すべてのボタンに共通する挙動をさせる関数
const buttonFunction = () => {
    quizIndex++;
    document.getElementById('buttons').style.display = "none";
    document.getElementById('nextbtnarea').style.display = "block";
    if(quizIndex < quizLength){
        //nextbtnというclassを2行目で取得して，for文でそれぞれのnextbtnに適用
        for(let i = 0; i < nextbtn.length; i++){
            nextbtn[i].addEventListener('click', () => {
                setupQuiz();
                MathJax.Hub.Typeset();
                document.getElementById('buttons').style.display = "block";
                document.getElementById('nextbtnarea').style.display = "none";
                //画面上部にスクロールさせる実装
                window.scroll({top: 0, behavior: 'instant'});
            });
        }
    } else {
        //問題がもうなければこちらを実行
        //nextbtnというclassを2行目で取得して，for文でそれぞれのnextbtnに適用
        for(let i = 0; i < nextbtn.length; i++){
            nextbtn[i].innerHTML = '診断結果へ' ;
            nextbtn[i].addEventListener('click', () => {
                if (score <5){
                    hantei = '中学生レベルです．1から見直した方がいいかもしれません．';
                } else if (score <10) {
                    hantei = 'まだまだこれからです．多くの分野で基礎レベルの欠如が見られますので至急対応しましょう．';
                } else if (score <14) {
                    hantei = 'それなりに基礎ができていますが，落とした問題を確認しましょう．';
                } else if (score <18) {
                    hantei = 'かなり基礎ができています．';
                } else if (score <19) {
                    hantei = '全問正解恐れ入りました．';
                }
                if (score == 18) {
                    swal.fire({
                        html: '<span style="font-size: xx-large; color: red">Excellent!</span>',
                        showConfirmButton : false,
                        padding : '3rem',
                        background : '#000000', //ダイアログ背景色
                        backdrop : 'linear-gradient(135deg,rgba(0,250,0,0.75) , rgba(250,250,0,0.75), rgba(250,0,250,0.75), rgba(0,0,250,0.75), rgba(0,250,250,0.75), rgba(250,0,00,0.75))', //外の背景色，透明度
                        timer : '1500'    //1.5秒後に閉じる
                    });
                    aryweak.push('ありませんでした!');
                }
                document.getElementById('front').style.display = "none";
                document.getElementById('nextbtnarea').style.display = "none";
                document.getElementById('kekka').style.display = "block";
                document.getElementById('getResult').style.display = "block";
                result.innerHTML += '<p>あなたの正解数は ' + quizIndex + ' 問中 <strong>' + score + ' </strong>問でした．</p><p>' + hantei + '</p><p style=\"text-align: center\">解けなかった問題：テーマ</p><p>' + aryweak.join('') + '</p>';
                //画面上部にスクロールさせる実装
                window.scroll({top: 0, behavior: 'smooth'});
                getResult.addEventListener('click',function twitText() {
                    var s, url;
                    s = "ファイナルチェック数学IAの結果は…%0a" + quizIndex + " 問中" + score + " 問でした．%0a" + hantei + "";
                    url = 'hiraocafe.com/note/finalcheck1a.html';
                    if (s != "") {
                        if (s.length > 140) {
                            //文字数制限
                            alert("テキストが140字を超えています");
                        } else {
                            //投稿画面を開く
                            url = "http://twitter.com/share?hashtags=ファイナルチェック数学IA&url=" + escape(url) + "&text=" + s;
                            window.open(url, "_blank", "width=600,height=300");
                        }
                    }
                }
                                          )
            });
        }
    }
}
setupQuiz();

// 問題のテーマを配列に格納．最後に解けなかった問題を提示するために必要
let ary = ['問題1：根号内の2乗<br>', '問題2：<a href=\"necessary_sufficient_condition.html\" target=\"_blank\">必要条件，十分条件の問題</a><br>', '問題3：逆,裏,対偶<br>', '問題4：<a href=\"2jikansumaxmin-jikumove.html\" target=\"_blank\">2次関数の最大最小(グラフ変動，定義域固定)</a><br>', '問題5：<a href=\"kainohaichi.html\" target=\"_blank\">2次方程式の解の配置問題</a><br>', '問題6：三角比総合問題(<a href=\"law-of-sines.html\" target=\"_blank\">正弦定理</a>,<a href=\"law-of-cosines.html\" target=\"_blank\">余弦定理</a>,<a href=\"3-edges-area.html\" target=\"_blank\">3辺既知の三角形の面積の出し方</a>,三角形の面積と内接円の半径)<br>', '問題7：中央値と四分位偏差<br>', '問題8：相関係数の計算(<a href=\"kyoubunsan.html\" target=\"_blank\">共分散のもう一つの出し方</a>)<br>', '問題9：変量の変換をした平均と分散<br>', '問題10：<a href=\"order-permutation.html\" target=\"_blank\">順序が定まった順列</a><br>', '問題11：<a href=\"kumiwake.html\" target=\"_blank\">組分け問題</a><br>', '問題12：不等式を満たす場合の数<br>', '問題13：反復試行の確率<br>', '問題14：条件付き確率<br>', '問題15：三角形の外心,内心,重心の定義<br>', '問題16：オイラーの多面体定理<br>', '問題17：正の約数の個数と総和<br>', '問題18：ユークリッドの互除法による特殊解を使う1次不定方程式(<a href=\"euclidtokushukai.html\" target=\"_blank\">ユークリッドの互除法による特殊解の求め方</a>)<br>'];

// aryにある解けなかった問題を格納するための配列
let aryweak = [];

//ボタンのプログラムをそれぞれボタン番号0〜3まで記載．$button[k]にrandbox[k]が対応．$button[k]が0番目の選択肢なら正解にする．
for(let k = 0; k < 4; k++){
    $button[k].addEventListener('click', () => {
        if (randbox[k] == 0) {
            //正解演出
            swal.fire({
                html: '<span style="font-size: x-large; color: red">Correct!</span>',
                showConfirmButton : false,
                padding : '2rem',
                background : '#000000', //ダイアログ背景色
                backdrop : 'linear-gradient(135deg,rgba(184,117,30,0.8),rgba(255,206,8,0.8),rgba(238,238,178,0.8),rgba(231,231,231,0.8),rgba(238,238,178,0.8),rgba(255,206,8,0.8),rgba(184,117,30,0.8))', //外の背景色，透明度
                timer : '500'    //0.7秒後に閉じる
            });
            score++;
        } else {
            //不正解演出
            swal.fire({
                html: '<span style="font-size: x-large; color: red">Wrong!</span>',
                showConfirmButton : false,
                padding : '2rem',
                background : '#000000', //ダイアログ背景色
                backdrop : 'rgba(0,0,0,0.75)', //外の背景色，透明度
                timer : '500'    //0.7秒後に閉じる
            });
            aryweak.push(ary[quizIndex]);
        }
        buttonFunction();
    });
}

//5番目のボタンだけ必ず不正解にする．不正解演出もなし
$button[4].addEventListener('click', () => {
    aryweak.push(ary[quizIndex]);
    buttonFunction();
});

```

quiz という配列が長いですね。

setupQuizという関数は、クイズの問題文、選択肢を決定する関数です。
0〜3までのランダムな順列を表現するために、while文を使って、異なる数字の順列になるようにしました。

それをrandbox という配列に格納します。これは、ボタン番号と問題番号を対応させるために必要です。

そしてすべてのボタンに共通する関数がbuttonFunctionです。問題番号を進ませ、buttonsとnextbtnareaの表示を切り替えます。
次の問題へボタンがクリックされたらsetupQuizを起動し(MathJax.Hub.Typeset();は数式表現を満足にするために必要です)、buttonsとnextbtnareaの表示を切り替えます。window.scrollは今の画面の場所に関わらず、問題文がすぐ見れるよう一番上に表示させるためのものです。
問題がもうないと、診断結果を出すボタンにします。そのボタンがクリックされると、scoreの値に応じて判定分を出し、frontとnextbtnareaとkekkaの表示を切り替えます。さらにそれをTwitterに引き渡すための処理も記述します。
ここまでがbuttonFunctionです。

aryは最後に解けなかった問題を提示するために必要です。またaryweakは解けなかった問題を格納するための空の配列です。

最後にボタンのイベントリスナーですが、クリックされたのが$button[k]でそれが0番目の選択肢なら正解にするのです。0番目の選択肢なら正解とanswersに決めて置いてあります。

5番目のボタンだけ必ず不正解にする、不正解演出もない特別なボタンです。いずれにせよ不正解かわからないボタンが押されるとaryweakにaryの対応したテーマが格納され、最後に表示されるわけです。

以上、素人なので、まだコードが綺麗にできるかと思いますが、自分の現在では最大限にリファクタリングした結果でございます。

遠慮なく、助言、感想いただけましたら幸いです。

では。