diff --git a/src/lib/array/shuffle-array.test.ts b/src/lib/array/shuffle-array.test.ts new file mode 100644 index 00000000..3dd875e1 --- /dev/null +++ b/src/lib/array/shuffle-array.test.ts @@ -0,0 +1,42 @@ +import {describe, it, expect} from 'vitest' +import {shuffleArray} from './shuffle-array.ts' + +describe('shuffleArray function', () => { + it('should shuffle an array of numbers', () => { + const array = [1, 2, 3, 4, 5]; + const shuffled = shuffleArray([...array]); + expect(shuffled).not.toEqual(array); + }); + + it('should shuffle by reference', () => { + const array = [1, 2, 3, 4, 5]; + const initialArray = [...array] + shuffleArray(array); + expect(array).not.toEqual(initialArray); + }); + + it('should shuffle an array of strings', () => { + const array = ['a', 'b', 'c', 'd', 'e']; + const shuffled = shuffleArray([...array]); + expect(shuffled).not.toEqual(array); + }); + + it('should handle an empty array', () => { + const array: unknown[] = []; + const shuffled = shuffleArray(array); + expect(shuffled).toEqual([]); + }); + + it('should retain all elements', () => { + const array = [1, 2, 3, 4, 5]; + const shuffled = shuffleArray([...array]); + expect(shuffled.sort()).toEqual(array.sort()); + }); + + it('should provide a random order', () => { + const array = [1, 2, 3, 4, 5]; + const firstShuffle = shuffleArray([...array]); + const secondShuffle = shuffleArray([...array]); + expect(firstShuffle).not.toEqual(secondShuffle); + }); +}); diff --git a/src/lib/array/shuffle-array.ts b/src/lib/array/shuffle-array.ts new file mode 100644 index 00000000..9af1c190 --- /dev/null +++ b/src/lib/array/shuffle-array.ts @@ -0,0 +1,15 @@ +export const shuffleArray = (array: T[]): T[] => { + let currentIndex = array.length, + randomIndex; + + while (currentIndex !== 0) { + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex--; + [array[currentIndex], array[randomIndex]] = [ + array[randomIndex], + array[currentIndex], + ]; + } + + return array; +}; diff --git a/src/store/card-under-review-store.ts b/src/store/card-under-review-store.ts index 27c19ae9..846621d8 100644 --- a/src/store/card-under-review-store.ts +++ b/src/store/card-under-review-store.ts @@ -21,6 +21,7 @@ export class CardUnderReviewStore { back: string; example: string | null = null; deckName?: string; + deckId?: number; deckSpeakLocale: string | null = null; deckSpeakField: string | null = null; @@ -33,6 +34,7 @@ export class CardUnderReviewStore { this.back = card.back; this.example = card.example; this.deckName = deck.name; + this.deckId = deck.id; this.deckSpeakLocale = deck.speak_locale; this.deckSpeakField = deck.speak_field; diff --git a/src/store/review-store.test.ts b/src/store/review-store.test.ts index e03fd2a6..dabc5bdc 100644 --- a/src/store/review-store.test.ts +++ b/src/store/review-store.test.ts @@ -65,6 +65,14 @@ vi.mock("./deck-list-store.ts", () => { }; }); +vi.mock('../lib/array/shuffle-array.ts', () => { + return { + shuffleArray: (array: unknown[]) => { + return array; + }, + }; +}) + const cardToSnapshot = (card: CardUnderReviewStore) => ({ back: card.back, deckName: card.deckName, diff --git a/src/store/review-store.ts b/src/store/review-store.ts index 863fa633..498039cb 100644 --- a/src/store/review-store.ts +++ b/src/store/review-store.ts @@ -8,6 +8,7 @@ import { deckListStore, DeckWithCardsWithReviewType, } from "./deck-list-store.ts"; +import { shuffleArray } from "../lib/array/shuffle-array.ts"; type ReviewResult = { forgotIds: number[]; @@ -37,10 +38,12 @@ export class ReviewStore { if (!deck.cardsToReview.length) { return; } - deck.cardsToReview.forEach((card) => { - this.cardsToReview.push(new CardUnderReviewStore(card, deck)); - }); + const cardsToReview = deck.cardsToReview.map( + (card) => new CardUnderReviewStore(card, deck), + ); + shuffleArray(cardsToReview); + this.cardsToReview = cardsToReview; this.initialCardCount = this.cardsToReview.length; this.currentCardId = this.cardsToReview[0].id; if (this.cardsToReview.length > 1) { @@ -59,11 +62,13 @@ export class ReviewStore { } myDecks.forEach((deck) => { - deck.cardsToReview + const cardsToRepeat = deck.cardsToReview .filter((card) => card.type === "repeat") - .forEach((card) => { - this.cardsToReview.push(new CardUnderReviewStore(card, deck)); - }); + .map((card) => new CardUnderReviewStore(card, deck)); + + shuffleArray(cardsToRepeat); + + this.cardsToReview.push(...cardsToRepeat); }); if (!this.cardsToReview.length) {