summaryrefslogtreecommitdiff
path: root/static/script.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/script.js')
-rw-r--r--static/script.js192
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">&middot;</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">&mdash;<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();