diff --git a/js/game.js b/js/game.js index 53f5988..d7e186f 100644 --- a/js/game.js +++ b/js/game.js @@ -6,21 +6,39 @@ /* global connectToPlayer, endTimer, playAll, stopClip */ /* global playClipButtons, startTimerButton, helpButton, guessInput, giveUpButton, remakeButton */ -/* global unguessedClips, revealSong, resetStartModal */ +/* global unguessedClips, unguessedArtistClips, revealSong, revealArtist, resetStartModal, isArtistMode */ /* global songClips */ const scoreSpan = document.getElementById('score-span'); const maxScoreSpan = document.getElementById('max-score-span'); +const artistScoreHolder = document.getElementById('artist-score-holder'); +const artistScoreSpan = document.getElementById('artist-score-span'); +const maxArtistScoreSpan = document.getElementById('max-artist-score-span'); + let gameStarted = false; function updateScore () { scoreSpan.innerText = songClips.length - unguessedClips.length; - if (unguessedClips.length === 0) { + if (isArtistMode()) { + + artistScoreSpan.innerText = songClips.length - unguessedArtistClips.length; + + if (unguessedClips.length === 0 && unguessedArtistClips.length === 0) { + + endGame(); + + } + + } else { + + if (unguessedClips.length === 0) { + + endGame(); - endGame(); + } } @@ -30,6 +48,9 @@ function initialiseScore () { scoreSpan.innerText = '0'; maxScoreSpan.innerText = songClips.length; + maxArtistScoreSpan.innerText = songClips.length; + + artistScoreHolder.style.display = isArtistMode() ? '' : 'none'; } @@ -37,6 +58,7 @@ function resetScore () { scoreSpan.innerText = '-'; maxScoreSpan.innerText = '-'; + maxArtistScoreSpan.innerText = '-'; } @@ -67,6 +89,16 @@ function endGame () { } + if (isArtistMode()) { + + for (let i = 0; i < unguessedArtistClips.length; i++) { + + revealArtist(i, 'red'); + + } + + } + stopClip(); guessInput.disabled = true; diff --git a/js/guesser.js b/js/guesser.js index 0c2e00a..7e6b4b4 100644 --- a/js/guesser.js +++ b/js/guesser.js @@ -5,7 +5,7 @@ *****************************************************************************/ /* global songClips */ -/* global endGame, updateScore */ +/* global endGame, updateScore, isArtistMode, updateProgressBarUI */ const MAX_DISTANCE = 1; @@ -14,7 +14,7 @@ let playClipButtons, songNameSpans, hyphenSpans, artistSpans; const guessInput = document.getElementById('guess-input'); const giveUpButton = document.getElementById('give-up-button'); -let unguessedClips; +let unguessedClips, unguessedArtistClips; function levenshtein (a, b) { @@ -78,27 +78,40 @@ function cleanString (input) { } -function isCloseMatch (userGuess, actualTitle) { +function isCloseMatch (userGuess, actualName) { const cleanedUserGuess = cleanString(userGuess); - const cleanedActualTitle = cleanString(actualTitle); - const distance = levenshtein(cleanedUserGuess, cleanedActualTitle); + const cleanedActualName = cleanString(actualName); + const distance = levenshtein(cleanedUserGuess, cleanedActualName); return distance <= MAX_DISTANCE; } +function revealArtist (index, colour) { + + const clip = unguessedArtistClips[index]; + + artistSpans[clip.index].innerText = clip.artists.map(artist => artist.name).join(', '); + artistSpans[clip.index].style.color = colour; + +} + function revealSong (index, colour) { const clip = unguessedClips[index]; songNameSpans[clip.index].innerText = clip.songName; - artistSpans[clip.index].innerText = clip.artists.map(artist => artist.name).join(', '); - songNameSpans[clip.index].style.color = colour; hyphenSpans[clip.index].style.color = colour; - artistSpans[clip.index].style.color = colour; + + if (!isArtistMode()) { + + artistSpans[clip.index].innerText = clip.artists.map(artist => artist.name).join(', '); + artistSpans[clip.index].style.color = colour; + + } } @@ -122,6 +135,7 @@ async function prepareUI () { artistSpans = document.getElementsByClassName('artist-span'); unguessedClips = JSON.parse(JSON.stringify(songClips)); + unguessedArtistClips = JSON.parse(JSON.stringify(songClips)); } @@ -133,6 +147,13 @@ function resetUI () { artistSpans = []; unguessedClips = []; + unguessedArtistClips = []; + +} + +function isArtistGuessed (i) { + + return !unguessedArtistClips.some(obj => obj.index === i); } @@ -142,9 +163,64 @@ function isGuessed (i) { } -guessInput.addEventListener('keyup', () => { +function checkArtistGuess (guess) { - const guess = guessInput.value; + let matchIndex = -1; + + unguessedArtistClips.forEach((clip, index) => { + + const artists = clip.artists; + + for (let i = 0; i < artists.length; i++) { + + const isMatch = isCloseMatch(guess, artists[i].name); + + if (isMatch) { + + matchIndex = index; + + } + + } + + }); + + if (matchIndex !== -1) { + + const artists = unguessedArtistClips[matchIndex].artists; + + // Let user type final letter if that is the only difference + + for (let i = 0; i < artists.length; i++) { + + const artist = artists[i].name; + + const likelyArtistName = cleanString(artist); + + if (likelyArtistName.substring(0, likelyArtistName.length - 1) === cleanString(guess)) { + + return; + + } + } + + console.log('Matched with', matchIndex); + + guessInput.value = ''; + + revealArtist(matchIndex, 'green'); + + unguessedArtistClips.splice(matchIndex, 1); + + updateScore(); + + updateProgressBarUI(); + + } + +} + +function checkSongGuess (guess) { let matchIndex = -1; @@ -182,6 +258,22 @@ guessInput.addEventListener('keyup', () => { updateScore(); + updateProgressBarUI(); + + } + +} + +guessInput.addEventListener('keyup', () => { + + const guess = guessInput.value; + + checkSongGuess(guess); + + if (isArtistMode()) { + + checkArtistGuess(guess); + } }); diff --git a/js/player.js b/js/player.js index 4da34b2..3cf2a80 100644 --- a/js/player.js +++ b/js/player.js @@ -5,7 +5,7 @@ *****************************************************************************/ /* global Spotify */ -/* global updateGuessUI, formatTimeMs, fillBar */ +/* global updateGuessUI, formatTimeMs, fillBar, updateProgressBarUI */ /* global token, songClips, unguessedClips, gameStarted */ /* global helpButton */ @@ -166,7 +166,7 @@ function startProgressBarLoop () { } - fillBar(currentClipIndex, 0); + fillBar(0); animationInterval = setInterval(() => { @@ -181,7 +181,7 @@ function startProgressBarLoop () { } - fillBar(currentClipIndex, currentPercentage); + fillBar(currentPercentage); } @@ -199,7 +199,7 @@ function endProgressBarLoop (newBarPercentage) { if (newBarPercentage) { - fillBar(currentClipIndex, newBarPercentage); + fillBar(newBarPercentage); } @@ -211,6 +211,8 @@ function playClip (trackUri, startTime, clipLength) { resumeButton.disabled = true; setStopResumeShown(true); + updateProgressBarUI(); + startTime = startTime === undefined ? 0 : startTime; const songName = songClips[currentClipIndex].songName; diff --git a/js/progressBar.js b/js/progressBar.js index ae00317..042ec85 100644 --- a/js/progressBar.js +++ b/js/progressBar.js @@ -4,8 +4,8 @@ * August 2024 *****************************************************************************/ -/* global songClips */ -/* global isGuessed */ +/* global songClips, currentClipIndex */ +/* global isGuessed, isArtistGuessed, isArtistMode */ const progressBarHolder = document.getElementById('progress-bar-holder'); let progressBars = []; @@ -50,45 +50,108 @@ function createProgressBars (onClick) { } -function fillBar (barIndex, percentage) { +function colourProgressBar (i) { - for (let i = 0; i < progressBars.length; i++) { + if (isArtistMode()) { - if (i < barIndex || (i === barIndex && percentage === 100)) { + if (isGuessed(i) && isArtistGuessed(i)) { - progressBars[i].style.width = '100%'; - progressBars[i].classList.remove('progress-bar-animated', 'bg-success'); + progressBars[i].classList.remove('progress-bar-animated', 'bg-current'); - if (isGuessed(i)) { + progressBars[i].classList.add('bg-correct'); + progressBars[i].classList.remove('bg-half'); - progressBars[i].classList.add('bg-info'); + } else if (isGuessed(i) !== isArtistGuessed(i)) { - } + progressBars[i].classList.remove('progress-bar-animated', 'bg-current'); - } else if (i === barIndex) { - - progressBars[i].style.width = percentage + '%'; - progressBars[i].classList.add('progress-bar-animated', 'bg-success'); + progressBars[i].classList.add('bg-half'); } else { + progressBars[i].classList.remove('bg-correct', 'bg-half'); + + } + + } else { + + if (isGuessed(i)) { + + progressBars[i].classList.remove('progress-bar-animated', 'bg-current'); + + progressBars[i].classList.add('bg-correct'); + + } + + } + +} + +function updateProgressBarUI () { + + for (let i = 0; i < progressBars.length; i++) { + + if (i < currentClipIndex) { + + progressBars[i].style.width = '100%'; + colourProgressBar(i); + + } else if (i > currentClipIndex) { + progressBars[i].style.width = '0%'; - progressBars[i].classList.remove('progress-bar-animated', 'bg-success'); + progressBars[i].classList.remove('progress-bar-animated', 'bg-current'); } const parent = progressBars[i].parentElement; - if (isGuessed(i)) { + if (isArtistMode()) { + + if (isArtistGuessed(i) && isGuessed(i)) { + + parent.classList.add('guessed'); + parent.classList.remove('half-guessed'); + + } else if (isArtistGuessed(i) !== isGuessed(i)) { + + parent.classList.add('half-guessed'); - parent.classList.add('guessed'); + } else { + + parent.classList.remove('guessed'); + parent.classList.remove('half-guessed'); + + } } else { - parent.classList.remove('guessed'); + if (isGuessed(i)) { + + parent.classList.add('guessed'); + + } else { + + parent.classList.remove('guessed'); + + } } } } + +function fillBar (percentage) { + + progressBars[currentClipIndex].style.width = percentage + '%'; + progressBars[currentClipIndex].classList.add('progress-bar-animated', 'bg-current'); + + if (percentage >= 100) { + + progressBars[currentClipIndex].style.width = '100%'; + + } + + colourProgressBar(currentClipIndex); + +} diff --git a/js/songClips.js b/js/songClips.js index e5b01c3..e79e379 100644 --- a/js/songClips.js +++ b/js/songClips.js @@ -9,7 +9,7 @@ /* global bootstrap */ /* global token, currentClipIndex, preselectedClips */ /* global stopButton, resumeButton, prevButton, nextButton */ -/* global prepareUI, resetUI, resumeClip, stopClip, pauseTimer, resumeTimer, addSecondsToTimer, playSpecificClip, playSpecificSong, seededRandom, generateWaveform, createProgressBars */ +/* global prepareUI, resetUI, resumeClip, stopClip, pauseTimer, resumeTimer, addSecondsToTimer, playSpecificClip, playSpecificSong, seededRandom, isArtistMode, createProgressBars */ const CLIP_LENGTH_MS = 8000; @@ -118,8 +118,11 @@ async function getRandomSongsFromPlaylist (playlistId, numberOfSongs, token, see } - // TODO: Only disable duplicates if artist scoring is enabled - allTracks = removeDuplicateArtists(allTracks); + if (isArtistMode()) { + + allTracks = removeDuplicateArtists(allTracks); + + } const randomSongs = getRandomSubset(allTracks, numberOfSongs, seed, offset); diff --git a/play.css b/play.css index 338916c..403d7d4 100644 --- a/play.css +++ b/play.css @@ -28,5 +28,21 @@ } .progress.guessed { - background-color: #87daea !important; + background-color: #a4f0a5 !important; } + +.progress.half-guessed { + background-color: #fbc19d !important; +} + +.progress-bar.bg-current { + background-color: #d23939 !important; +} + +.progress-bar.bg-correct { + background-color: #36a853 !important; +} + +.progress-bar.bg-half { + background-color: #f0820d !important; +} \ No newline at end of file diff --git a/play.html b/play.html index e261ee4..8a57a50 100644 --- a/play.html +++ b/play.html @@ -23,11 +23,15 @@