diff options
author | cyfraeviolae <cyfraeviolae> | 2022-02-25 16:26:02 -0500 |
---|---|---|
committer | cyfraeviolae <cyfraeviolae> | 2022-02-25 16:26:02 -0500 |
commit | 36af38bb79f2310138853f59f4aff18908ad5abc (patch) | |
tree | d396acef4e08d038727ae93701c56b15ef69dd65 /static/script.js |
init
Diffstat (limited to 'static/script.js')
-rw-r--r-- | static/script.js | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/static/script.js b/static/script.js new file mode 100644 index 0000000..552da72 --- /dev/null +++ b/static/script.js @@ -0,0 +1,192 @@ +"use strict"; + +var entryEl = document.getElementById("entry") +var guessesEl = document.getElementById("guesses") +var winEl = document.getElementById("win") + +function renderWord(word, wordIdx, guess, score, offset) { + var els = [] + var c = 0; + for (var syllable of word) { + var sylEls = [] + + var shouldStress = syllable[0] == "/"; + if (shouldStress) { + syllable = syllable.slice(1) + } + var stress = shouldStress ? "stress" : "" + for (var _ in syllable) { + var charclass = '' + var able = '' + if (score) { + if (score.greens[c]) { + charclass += 'green' + } else if (score.yellows[c]) { + charclass += 'yellow' + } else if (score.greys[c]) { + charclass += 'grey' + } + able = 'disabled' + } + var val = guess ? guess[wordIdx][c] : '' + var typ = guess ? 'solbox' : 'entrybox' + sylEls.push(`<input data-word="${wordIdx}" data-character="${c}" data-offset="${c+offset}" class="box ${typ} ${charclass}" type="text" maxlength="1" required title="A-Z only" value="${val}" pattern="[A-Za-z]" ${able}></input>`) + c++; + } + + els.push(`<div class="syllable ` + stress + `">` + sylEls.join('') + `</div>`) + } + + return `<div class="word">` + els.join(`<div class="syllable-sep">·</div>`) + `</div>` +} + +function renderLine(line, guess, scores) { + var els = [] + var offset = 0; + for (var wordIdx in line) { + var word = line[wordIdx] + els.push(renderWord(word, wordIdx, guess, scores && scores[wordIdx], offset)) + offset += word.join('').replaceAll('/', '').length + console.log(word, word.join('').replaceAll('/', '').length) + } + return `<div class="line">` + els.join('') + `</div>` +} + +function consumeInput() { + var els = Array.from(document.getElementsByClassName("entrybox")); + els.sort((x, y) => { + var xword = x.getAttribute('data-word') + var xchar = x.getAttribute('data-character') + var yword = y.getAttribute('data-word') + var ychar = y.getAttribute('data-character') + + if (xword != yword) { + return xword - yword; + } + return xchar - ychar; + }) + var words = {} + for (var el of els) { + words[el.getAttribute('data-word')] = (words[el.getAttribute('data-word')] || '') + + el.value.toUpperCase() + } + return words +} + +function scoreLine(guess, answer) { + var scores = [] + for (var idx in guess) { + var guessword = guess[idx] + var answerword = answer[idx].join('').replaceAll('/', '').toUpperCase() + scores.push(scoreWord(guessword, answerword)) + } + return scores +} + +function scoreWord(guess, answer) { + var greens = {} + var yellows = {} + var greys = {} + var counts = {} + var placed = {} + for (var idx in guess) { + if (guess[idx] == answer[idx]) { + greens[idx] = 1 + placed[answer[idx]] = (placed[answer[idx]] || 0) + 1 + } + counts[answer[idx]] = (counts[answer[idx]] || 0) + 1 + } + for (var idx in guess) { + if (greens[idx]) { + continue + } + if ((placed[guess[idx]] || 0) < counts[guess[idx]]) { + yellows[idx] = 1 + placed[guess[idx]] = (placed[guess[idx]] || 0) + 1; + } else { + greys[idx] = 1 + } + } + return {greens: greens, yellows: yellows, greys: greys} +} + +document.getElementById('clear').onclick = function(e) { + e.preventDefault(); + for (var el of document.getElementsByClassName('entrybox')) { + el.value = '' + } + document.querySelector(`[data-offset="0"]`).focus(); +} + +document.getElementById('game').addEventListener('submit', function(e) { + var guess = consumeInput() + guesses.push(guess) + var scores = scoreLine(guess, challenge.line) + var linehtml = renderLine(challenge.line, guess, scores) + guessesEl.innerHTML = linehtml + guessesEl.innerHTML + var win = true; + for (var score of scores) { + if (Object.keys(score.yellows).length || Object.keys(score.greys).length) { + win = false; + } + } + if (win) { + entryEl.innerHTML = linehtml + winGame(challenge) + } +}) + +function winGame(challenge) { + winEl.style = 'display: block;' + document.getElementById('btns').style = 'display: none;' + document.getElementById('meter').innerText = challenge.meter + document.getElementById('ctx').innerHTML = challenge.ctx.replaceAll(/^(.*)/gm, '\t$1') + `\n\t<span class="byline">—<a href="${challenge.link}">${challenge.title}</a>, ${challenge.collection}, ${challenge.author}</span>` + var date = new Date().toISOString().slice(0, 10) + var firstguess = Object.values(guesses[0]).join(' ') + document.getElementById('share').value = `I solved the ${date} Prosodyle at cyfraeviolae.org/prosodyle. My first guess was: "${firstguess}".` +} + +document.getElementById('entry').addEventListener('keydown', function(e) { + if (!Array.from(e.target.classList).includes('entrybox')) { + return; + } + if (e.ctrlKey || e.altKey || (e.key.length != 1 && e.key != 'Backspace')) { + return; + } + e.preventDefault(); + var offset = parseInt(e.target.getAttribute('data-offset')) + var el; + if (e.key == 'Backspace') { + e.target.value = ''; + el = document.querySelector(`[data-offset="${offset-1}"]`); + } else { + e.target.value = e.key; + el = document.querySelector(`[data-offset="${offset+1}"]`); + } + if (el) { + el.focus(); + } +}) + +function getDailyChallenge() { + // https://stackoverflow.com/a/8619946 + var now = new Date(); + var start = new Date(now.getFullYear(), 0, 0); + var diff = now - start; + var oneDay = 1000 * 60 * 60 * 24; + var day = Math.floor(diff / oneDay); + // end snippet + return challenges[day-56] +} + +document.getElementById('copy').addEventListener('click', function(e) { + e.preventDefault(); + document.getElementById('share').select() + document.execCommand('copy'); +}) + + +var guesses = [] +var challenge = getDailyChallenge() +entryEl.innerHTML = renderLine(challenge.line) +document.querySelector(`[data-offset="0"]`).focus(); |