"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 ``
}
function renderChallengeIdxBox() {
return ``
}
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() {
return 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"]`));
}