FEATUREわかったつもりの、その先へ
知る・学ぶ

選択肢をシャッフルしても正解がずれない仕組み|ワインQの4択で考える

4択を並べ替えたら、正解の位置も変わるはず。ワインQの処理を使い、選択肢と正解情報を一緒に動かす方法を図解します。固定乱数の作例、24通りの交換パターン、200問を使った検証結果も紹介します。

CONTENTSこの記事の目次7項目

ワインQの出題処理を確かめるため、説明用の4択「赤・青・緑・黄」を並べ替えてみました。正解を「青」にすると、検証後の並びは「緑・黄・青・赤」。正解の内容は同じでも、位置は2番目から3番目へ移っています。ここで正解位置だけを元のままにしたら、採点はどうなるでしょうか。

画面をランダムに並べることと、データの意味を保つことは別の課題です。ワインQでは選択肢へ正解の印を付けて一緒に動かし、並べ替えた後で正解位置を求め直しています。

問題順と選択肢順、2つの並べ替えがある

クイズ開始時には、選択カテゴリに合う問題を集め、問題の配列をシャッフルしてから出題数だけ取り出します。続いて、各問題の4つの選択肢もシャッフルします。問題をどの順番で出すかと、答えをどの位置へ置くかは別々の処理です。

選択肢はoptions、正解の位置はcorrectIndexで表します。配列の位置は0から始まるため、「赤・青・緑・黄」の青は位置1です。並べ替え後もcorrectIndexを1のままにすると、今度は黄を正解として扱ってしまいます。

正解の印を、選択肢に付けてから動かす

ワインQでは、まず各選択肢を「文字列とisCorrectという正解の印」の組にします。この組をシャッフルした後、文字列だけを取り出して新しいoptionsにし、正解の印がある場所を探してcorrectIndexを更新します。

こうすると正解の根拠は「元の何番目だったか」ではなく、移動する選択肢に結び付きます。表を並べ替えるときに、名前の列だけを動かして点数を置き去りにしてはいけないのと同じです。

オリジナル説明図。説明用の色の4択に、固定した乱数0・0.5・0を順番に与えた作例です。実サービスの問題や乱数設定を変更したものではありません。

末尾から交換すると、何が起きる?

現行のshuffle関数は元配列をコピーし、末尾から順に「まだ確定していない範囲」の位置を1つ選んで交換します。Fisher–Yates型の並べ替えです。4択なら、交換相手の候補数は4、3、2と減っていきます。自分自身の位置が選ばれる場合もあります。

  • 位置3の交換相手を、位置0〜3から選ぶ。
  • 位置2の交換相手を、位置0〜2から選ぶ。
  • 位置1の交換相手を、位置0〜1から選ぶ。
  • 各交換では、選択肢と正解の印をセットで移動する。

交換相手はMath.floor(Math.random() * (index + 1))で求めます。Math.random()が返す0以上1未満の数を候補数倍し、小数点以下を切り捨てることで、0からindexまでの整数にします。今回の作例では乱数を0、0.5、0に固定したので、交換相手は順に0、1、0になりました。

配列のコピーは浅いコピーですが、今回の処理は要素の順番を交換するもので、元の選択肢文字列や問題オブジェクトの中身を書き換えません。選択肢の並びと正解位置を持つ新しい問題オブジェクトを返します。

「正解が保たれる」を実際に検証する

2026年9月12日のWineQuiz.tsxからshuffleとshuffleQuestionOptionsを抽出し、独立したローカル検証で実行しました。関数を書き直した説明用の処理ではなく、現在の関数へ作例データと固定乱数を渡しています。

実行結果を表示したローカルレポートのキャプチャ。24通りは交換相手の組み合わせを列挙した検証で、乱数を24回引いた結果ではありません。
  • 色の4択:4×3×2の全24交換パターンで、24種類の並びになることを確認。
  • 各パターン:選択肢の欠落・重複がなく、正解の内容が青のままであることを確認。
  • 実際の問題集200問:各問に3パターンの固定乱数を与え、計600ケースで正解の内容と選択肢の集合を確認。
  • 入力データ:呼び出し前後で元の問題が変わらないことも確認。

採点では、選んだ位置を問題IDごとに記録し、並べ替え後のcorrectIndexと比較します。つまり、表示に使った並びと、採点に使う正解位置を同じ問題データにそろえています。元の問題集の正解位置をそのまま参照して採点する処理ではありません。

検証に通ったことと、公平な乱数であることは違う

今回確かめたのは、並べ替えがデータの対応関係を壊さないことです。Math.random()が実際に作る分布や、長期的な出題頻度を測定したわけではありません。各交換相手を偏りなく選べることが、各並びを偏りなく作るための前提になります。

また、ランダムだから毎回必ず違う並びになるとは限りません。同じ並びが再び出ることもあります。Math.random()は暗号学的に安全な乱数源ではなく、このクイズの実装をそのまま秘密値の生成や厳密な抽選へ転用できるとは考えないようにしましょう。

並べ替える前に、何を一緒に動かすか

シャッフルで確認したいのは、見た目がばらばらになったかだけではありません。「なくなった要素はないか」「重複していないか」「正解やIDとの対応は残っているか」「元データを壊していないか」。この4点を押さえると、並べ替えは画面の演出から、意味を守るデータ処理として理解できます。

READ MOREワインQの使い方と公開時の記録実際のクイズと、問題を見返す使い方を紹介しています。

参考資料・確認範囲

  • ECMAScript仕様「Math.random」、MDN Web Docs「Math.random()」。値の範囲と用途上の注意を確認。
  • Appli ParkのWineQuiz.tsxとquestions.ts。2026年9月12日の実装を抽出して検証。24交換パターンと600ケースの結果は、問題の知識内容や乱数品質を保証するものではありません。