Randomizing Questions & Options
By default, the SdashAPI `limit=40` parameter pulls 40 random questions from the database. However, they are returned in whatever order the database happens to spit them out. For true CBT authenticity, we should actively shuffle the array on the frontend, and more importantly, shuffle the options (A, B, C, D) so the answer isn't always the same letter.
The Fisher-Yates Shuffle
3.14.1First, let's add a robust array shuffling function to our utility file (or the bottom of app.js). The Fisher-Yates algorithm is the industry standard for unbiased array randomization.
function shuffleArray(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle...
while (currentIndex !== 0) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
}
return array;
}Shuffling the API Response
3.14.2Now, right after you await response.json() in your fetch request, pass the data array through the shuffle function before saving it to your global state.
// Inside the Start button click listener const data = await response.json(); // Shuffle the entire test! examQuestions = shuffleArray(data.data);
Shuffling the Options
3.14.3Shuffling the options (A, B, C, D) is trickier because SdashAPI returns them as an Object, not an Array, and the answer property relies on the original object keys. The safest way is to shuffle an array of the keys (['a', 'b', 'c', 'd']) and map over that when rendering.
// Inside renderQuestion()
const originalKeys = Object.keys(qData.option); // ['a', 'b', 'c', 'd']
// Shuffle the keys if they haven't been shuffled yet for this specific question
if (!qData.shuffledKeys) {
qData.shuffledKeys = shuffleArray([...originalKeys]);
}
// Render options based on the newly randomized order
qData.shuffledKeys.forEach(key => {
const text = qData.option[key];
if (!text) return;
// Render the option UI...
// (Note: you might want to re-label them visually as A, B, C, D based
// on their new loop index rather than their original database key)
});