"use strict"; function renderScansion(scansion) { var s = '' for (var c of scansion) { if (c == '/') { s += '/' } else { s += '×' } } return s; } function renderWord(word, wordIdx, guess, score, offset) { var els = [] for (var c in word) { c = parseInt(c) var charclass = '' if (score) { if (score.greens[c]) { charclass += 'green' } else if (score.yellows[c]) { charclass += 'yellow' } else if (score.greys[c]) { charclass += 'grey' } } var val = guess ? guess[wordIdx][c] : '' var typ = guess ? 'solbox' : 'entrybox' els.push(`
${val}
`) } if (typeof challenge.scansion === "string") { var fullScansion = challenge.scansion.split(' ') } else { var fullScansion = challenge.scansion } var scansion = renderScansion(fullScansion[wordIdx]) var scansionBox = guess ? '' : `
${scansion}
` return `
${scansionBox}${els.join('')}
` } function renderGuessIdxBox(guessIdx) { return `
📋 ${guessIdx+1}
` } function renderChallengeIdxBox() { return `
#${challengeIdx + 1}
` } function renderLine(line, guess, guessIdx, scores) { var els = [] var offset = 0; if (guessIdx || guessIdx === 0) { els.push(renderGuessIdxBox(guessIdx)) } else { els.push(renderChallengeIdxBox()) } for (var wordIdx in line) { var word = line[wordIdx] els.push(renderWord(word, wordIdx, guess, scores && scores[wordIdx], offset)) offset += word.length } return `
` + els.join('') + `
` } function consumeInput() { var els = Array.from(document.getElementsByClassName("entrybox")); for (var el of els) { if (el.innerText.trim().length == '') { return null } } els.sort((x, y) => { var xword = x.getAttribute('data-word') var xchar = x.getAttribute('data-offset') var yword = y.getAttribute('data-word') var ychar = y.getAttribute('data-offset') 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.innerText.trim().toUpperCase() } return words } function scoreLine(guess, answer) { var scores = [] for (var idx in guess) { var guessword = guess[idx] var answerword = answer[idx].toUpperCase() var score = scoreWord(guessword, answerword) scores.push(score) if (!information[idx]) { information[idx] = {greens:{}, yellows:{}, greys:{}, greensrev:{}} } for (var i in score.greens) { information[idx].greens[guessword[i]] = 1 information[idx].greensrev[i] = guessword[i] } for (var i in score.yellows) { information[idx].yellows[guessword[i]] = 1 } for (var i in score.greys) { information[idx].greys[guessword[i]] = 1 } } 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} } function renderKeyboardLights() { for (var kel of document.getElementsByClassName('key')) { kel.classList.remove('yellowkey') kel.classList.remove('greenkey') kel.classList.remove('greykey') } var el = document.querySelector(`[data-offset="${focused}"]`); if (!el) { return } var info = information[el.getAttribute('data-word')] if (!info) { return } for (var kel of document.getElementsByClassName('key')) { if (info.greens[kel.getAttribute('data-key')]) { kel.classList.remove('greykey') kel.classList.remove('yellowkey') kel.classList.add('greenkey') } else if (info.yellows[kel.getAttribute('data-key')]) { kel.classList.remove('greykey') kel.classList.remove('greenkey') kel.classList.add('yellowkey') } else if (info.greys[kel.getAttribute('data-key')]) { kel.classList.remove('yellowkey') kel.classList.remove('greenkey') kel.classList.add('greykey') } } } var focused = null; function hasWon(scores) { for (var score of scores) { if (Object.keys(score.yellows).length || Object.keys(score.greys).length) { return false; } } return true; } function winGame(challenge) { winEl.style = 'display: block;' document.getElementById('win-idx-box').innerHTML = renderChallengeIdxBox() document.getElementById('btns').style = 'display: none;' document.getElementById('meter').innerText = challenge.meter var collection = challenge.collection ? `${challenge.collection}, ` : "" var ctx = challenge.ctx.replace(/^\n/, '').replace(/\n$/, '').replaceAll(/^(.*)/gm, ' $1') document.getElementById('ctx').innerHTML = ctx + `\n\t${challenge.title}\n\t\t${collection}${challenge.author}` var firstguess = Object.values(guesses[0]).join(' ') document.getElementById('share').value = `I solved Prosodyle #${challengeIdx+1} at cyfraeviolae.org/prosodyle. My first guess was: "${firstguess}."` } function keyHandler(key) { if (key == 'Enter') { document.getElementById('check').click() return; } var el = document.querySelector(`[data-offset="${focused}"]`); if (!el) { return; } if (!el.classList.contains('entrybox')) { return; } var offset = parseInt(el.getAttribute('data-offset')) var nextel; if (key == 'Backspace') { el.innerText = ''; nextel = document.querySelector(`[data-offset="${offset-1}"]`); } else if (key == 'ArrowLeft') { nextel = document.querySelector(`[data-offset="${offset-1}"]`); } else if (key == 'ArrowRight') { nextel = document.querySelector(`[data-offset="${offset+1}"]`); } else { el.innerText = key.toUpperCase(); nextel = document.querySelector(`[data-offset="${offset+1}"]`); } if (nextel) { focus(nextel); unfocus(el); } } document.addEventListener('keydown', function(e) { if (e.ctrlKey || e.altKey || (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".includes(e.key.toUpperCase()) && e.key != 'Backspace' && e.key != 'Enter' && e.key != 'ArrowLeft' && e.key != 'ArrowRight')) { return; } if (e.target.id == 'share') { return; } e.preventDefault(); keyHandler(e.key) }) document.addEventListener('mousedown', function(e) { if (Array.from(e.target.classList).includes('entrybox')) { e.preventDefault(); unfocus(document.querySelector(`[data-offset="${focused}"]`)); focus(e.target); } else if (Array.from(e.target.classList).includes('key')) { e.preventDefault(); var k = e.target.getAttribute('data-key') keyHandler(k) } else if (Array.from(e.target.classList).includes('idxbox')) { e.preventDefault(); var guessIdx = e.target.getAttribute('data-guess') var guess = guesses[guessIdx] var els = Array.from(document.getElementsByClassName("entrybox")); for (var el of els) { el.innerText = guess[el.getAttribute('data-word')][el.getAttribute('data-word-offset')] } } }) // from https://stackoverflow.com/a/8619946 function getDayOfYear() { 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); return day; } function getChallengeIdx() { var idx = getDayOfYear() - 57 return Math.min(idx, challenges.length-1) } function focus(el) { focused = parseInt(el.getAttribute('data-offset')) el.classList.add('focus') renderKeyboardLights() } function unfocus(el) { el.classList.remove('focus') } function renderLevels() { var s = ''; console.log('ok') for (var idx in challenges) { console.log(idx) var challenge = challenges[idx] s += `
  • ${challenge.meter}` var stored = localStorage.getItem("challenge" + idx) console.log(stored) if (stored) { var store = JSON.parse(stored) guesses = store.guesses information = store.information if (guesses.length) { if (hasWon(scoreLine(guesses[guesses.length - 1], challenge.line))) { s += ' · ' s += challenge.author s += ' · ' if (challenge.renderLine) { s += '' + challenge.renderLine + '' } else { s += '' + challenge.line.join(' ') + '' } } else { s += ' · in progress' } } } s += '
  • ' } return s } var levelsEl = document.getElementById('levels') var isLevelSelect = !!levelsEl var guesses = [] var information = {} if (isLevelSelect) { levelsEl.innerHTML = renderLevels() } else { var entryEl = document.getElementById("entry") var guessesEl = document.getElementById("guesses") var winEl = document.getElementById("win") document.getElementById('copy').addEventListener('click', function(e) { e.preventDefault(); document.getElementById('share').select() document.execCommand('copy'); }) document.getElementById('clear').onclick = function(e) { e.preventDefault(); for (var el of document.getElementsByClassName('entrybox')) { el.innerText = '' } unfocus(document.querySelector(`[data-offset="${focused}"]`)); focus(document.querySelector(`[data-offset="0"]`)) } Array.from(document.getElementsByClassName('reset-level')).forEach(function(element) { element.addEventListener('click', function(e) { e.preventDefault(); if (window.confirm("Are you sure you want to reset this level? All data will be permanently lost.")) { var stored = localStorage.removeItem("challenge" + challengeIdx) location.reload(); } }); }); document.getElementById('fill-green').addEventListener('click', function(e) { e.preventDefault(); var el = document.querySelector(`[data-offset="${focused}"]`) if (!el) { return } var w = el.getAttribute('data-word') for (var el of document.getElementsByClassName('entrybox')) { if (el.getAttribute('data-word') != w) { continue } var c = information[el.getAttribute('data-word')].greensrev[el.getAttribute('data-word-offset')] if (c) { el.innerText = c } else { el.innerText = '' } } }) document.getElementById('check').addEventListener('click', function(e) { var guess = consumeInput() if (guess == null) { return; } var guessIdx = guesses.length; guesses.push(guess) var scores = scoreLine(guess, challenge.line) localStorage.setItem("challenge" + challengeIdx, JSON.stringify({guesses: guesses, information: information})) var linehtml = renderLine(challenge.line, guess, guessIdx, scores) guessesEl.innerHTML = linehtml + guessesEl.innerHTML renderKeyboardLights() var win = hasWon(scores) if (win) { entryEl.style = 'display: none;' winGame(challenge) } }) var urlParams = new URLSearchParams(window.location.search); var challengeRequest = urlParams.get('challenge'); var challenge; var challengeIdx; if (challengeRequest) { challengeIdx = Number(challengeRequest) - 1 } else { challengeIdx = getChallengeIdx() } challenge = challenges[challengeIdx] entryEl.innerHTML = renderLine(challenge.line) var stored = localStorage.getItem("challenge" + challengeIdx) if (stored) { var store = JSON.parse(stored) guesses = store.guesses information = store.information for (var [guessIdx, guess] of guesses.entries()) { var scores = scoreLine(guess, challenge.line) var linehtml = renderLine(challenge.line, guess, guessIdx, scores) guessesEl.innerHTML = linehtml + guessesEl.innerHTML } var win = true; renderKeyboardLights() for (var score of scores) { if (Object.keys(score.yellows).length || Object.keys(score.greys).length) { win = false; } } if (win) { entryEl.style = 'display: none;' winGame(challenge) } } focus(document.querySelector(`[data-offset="0"]`)); }