11'use client' ;
22
3- import { useEffect , useRef , useState } from 'react' ;
3+ import { useEffect , useRef , useState , useMemo } from 'react' ;
44import Prism from 'prismjs' ;
55import 'prismjs/components/prism-javascript' ;
66import type { Question } from '@/lib/types' ;
77import { CodePlayground } from './CodePlayground' ;
8+ import { shuffleArray } from '@/lib/utils' ;
89
910interface QuestionRendererProps {
1011 question : Question ;
@@ -28,6 +29,22 @@ function QuestionRendererContent({
2829 // Derive usePlayground - disable if question requires non-strict mode
2930 const usePlayground = question . nonStrictMode ? false : usePlaygroundInternal ;
3031
32+ const { shuffledOptions, shuffledToOriginal, originalToShuffled } = useMemo ( ( ) => {
33+ const indices = question . options . map ( ( _ , i ) => i ) ;
34+ const shuffledIndices = shuffleArray ( indices ) ;
35+
36+ const shuffledOptions = shuffledIndices . map ( i => question . options [ i ] ) ;
37+ const shuffledToOriginal = new Map < number , number > ( ) ;
38+ const originalToShuffled = new Map < number , number > ( ) ;
39+
40+ shuffledIndices . forEach ( ( originalIndex , shuffledIndex ) => {
41+ shuffledToOriginal . set ( shuffledIndex , originalIndex ) ;
42+ originalToShuffled . set ( originalIndex , shuffledIndex ) ;
43+ } ) ;
44+
45+ return { shuffledOptions, shuffledToOriginal, originalToShuffled } ;
46+ } , [ question . options ] ) ;
47+
3148 useEffect ( ( ) => {
3249 if ( question . code && codeRef . current ) {
3350 Prism . highlightElement ( codeRef . current ) ;
@@ -162,9 +179,11 @@ function QuestionRendererContent({
162179 ) }
163180
164181 < div className = "space-y-2" >
165- { question . options . map ( ( option , index ) => {
166- const isSelected = selectedAnswer === index ;
167- const isCorrect = index === question . correctAnswer ;
182+ { shuffledOptions . map ( ( option , shuffledIndex ) => {
183+ const originalIndex = shuffledToOriginal . get ( shuffledIndex ) ! ;
184+ const isSelected = selectedAnswer === originalIndex ;
185+ const correctShuffledIndex = originalToShuffled . get ( question . correctAnswer ) ;
186+ const isCorrect = correctShuffledIndex !== undefined && shuffledIndex === correctShuffledIndex ;
168187
169188 let buttonClass = 'option-button-compact' ;
170189
@@ -180,14 +199,21 @@ function QuestionRendererContent({
180199
181200 return (
182201 < button
183- key = { index }
184- onClick = { ( ) => ! disabled && onSelectAnswer ?.( index ) }
202+ key = { shuffledIndex }
203+ onClick = { ( ) => {
204+ if ( ! disabled && onSelectAnswer ) {
205+ const originalIdx = shuffledToOriginal . get ( shuffledIndex ) ;
206+ if ( originalIdx !== undefined ) {
207+ onSelectAnswer ( originalIdx ) ;
208+ }
209+ }
210+ } }
185211 disabled = { disabled }
186212 className = { buttonClass }
187213 >
188214 < div className = "flex items-center gap-3" >
189215 < span className = "option-letter-compact" >
190- { String . fromCharCode ( 65 + index ) }
216+ { String . fromCharCode ( 65 + shuffledIndex ) }
191217 </ span >
192218 < span className = "flex-1 text-left text-sm" > { option } </ span >
193219 { showCorrect && isCorrect && (
0 commit comments