diff --git a/lib/dailyPuzzle.ts b/lib/dailyPuzzle.ts index 4b58b8f..054bcda 100644 --- a/lib/dailyPuzzle.ts +++ b/lib/dailyPuzzle.ts @@ -29,9 +29,7 @@ export async function getOrCreateDailyPuzzle(genre: Genre | null = null) { const allSongs = await prisma.song.findMany({ where: whereClause, include: { - puzzles: { - where: { genreId: genreId } - }, + puzzles: true, // Load ALL puzzles, not just for this genre (to use total activations) }, }); @@ -40,28 +38,24 @@ export async function getOrCreateDailyPuzzle(genre: Genre | null = null) { return null; } - // Calculate weights - const weightedSongs = allSongs.map(song => ({ + // Find songs with the minimum number of activations (all puzzles, not just for this genre) + // Only select from songs with the fewest activations to ensure fair distribution + const songsWithActivations = allSongs.map(song => ({ song, - weight: 1.0 / (song.puzzles.length + 1), + activations: song.puzzles.length, })); - // Calculate total weight - const totalWeight = weightedSongs.reduce((sum, item) => sum + item.weight, 0); + // Find minimum activations + const minActivations = Math.min(...songsWithActivations.map(item => item.activations)); - // Pick a random song based on weights using cumulative weights - // This ensures proper distribution and handles edge cases - let random = Math.random() * totalWeight; - let selectedSong = weightedSongs[weightedSongs.length - 1].song; // Fallback to last song + // Filter to only songs with minimum activations + const songsWithMinActivations = songsWithActivations + .filter(item => item.activations === minActivations) + .map(item => item.song); - let cumulativeWeight = 0; - for (const item of weightedSongs) { - cumulativeWeight += item.weight; - if (random <= cumulativeWeight) { - selectedSong = item.song; - break; - } - } + // Randomly select from songs with minimum activations + const randomIndex = Math.floor(Math.random() * songsWithMinActivations.length); + const selectedSong = songsWithMinActivations[randomIndex]; // Create the daily puzzle try { @@ -141,7 +135,7 @@ export async function getOrCreateSpecialPuzzle(special: Special) { song: { include: { puzzles: { - where: { specialId: special.id } + where: { specialId: special.id } // For specials, only count puzzles within this special } } } @@ -150,25 +144,25 @@ export async function getOrCreateSpecialPuzzle(special: Special) { if (specialSongs.length === 0) return null; - // Calculate weights - const weightedSongs = specialSongs.map(specialSong => ({ + // Find songs with the minimum number of activations within this special + // Note: For specials, we only count puzzles within the special (not all puzzles), + // since specials are curated, separate lists + const songsWithActivations = specialSongs.map(specialSong => ({ specialSong, - weight: 1.0 / (specialSong.song.puzzles.length + 1), + activations: specialSong.song.puzzles.length, })); - const totalWeight = weightedSongs.reduce((sum, item) => sum + item.weight, 0); - let random = Math.random() * totalWeight; - let selectedSpecialSong = weightedSongs[weightedSongs.length - 1].specialSong; // Fallback to last song + // Find minimum activations + const minActivations = Math.min(...songsWithActivations.map(item => item.activations)); - // Pick a random song based on weights using cumulative weights - let cumulativeWeight = 0; - for (const item of weightedSongs) { - cumulativeWeight += item.weight; - if (random <= cumulativeWeight) { - selectedSpecialSong = item.specialSong; - break; - } - } + // Filter to only songs with minimum activations + const songsWithMinActivations = songsWithActivations + .filter(item => item.activations === minActivations) + .map(item => item.specialSong); + + // Randomly select from songs with minimum activations + const randomIndex = Math.floor(Math.random() * songsWithMinActivations.length); + const selectedSpecialSong = songsWithMinActivations[randomIndex]; try { dailyPuzzle = await prisma.dailyPuzzle.create({