summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--index.html97
-rw-r--r--static/poems.js3
-rw-r--r--static/script.js122
-rw-r--r--static/styles.css96
4 files changed, 179 insertions, 139 deletions
diff --git a/index.html b/index.html
index 099e782..22bfab0 100644
--- a/index.html
+++ b/index.html
@@ -18,66 +18,67 @@
<a href="https://cyfraeviolae.org/git/prosodyle">source code</a>
</div>
<p>
- The dithyrambic sorcerer Roseacrucis has breached the Library&rsquo;s security measures and encrypted its
- treasured poetry collections. As our newest acolyte, your task is to decode one secret line of poetry each day.
+ The dithyrambic sorcerer Roseacrucis has encrypted the
+ Library&rsquo;s treasured poetry collections. As our newest
+ acolyte, your task is to decode one secret line of poetry each day.
</p>
<p>
- For the ransom price of one new line with the same metrical and syllabic structure as today&rsquo;s secret
- line, Roseacrucis will reveal which letters are in the right place 🟩, in the right word but in a different
+ Given the ransom price of one new line in the same meter as today&rsquo;s secret
+ line, for each word, Roseacrucis will reveal which letters are in the right place 🟩, in the word but in the wrong
place 🟨, or not in the word at all ⬜.
</p>
+ <p>
+ Each word is annotated with the number of required syllables and their stress marks. For example,
+ <span class="scansion">&times;&sol;</span> indicates that the word has two syllables, the first unstressed and the second
+ stressed (such as in <em>por-TRAY</em>).
+ </p>
<noscript>Sorry, JavaScript is required to play Prosodyle.</noscript>
<br>
<form id="game" action="javascript:void(0);" method="none">
- <p>
- Write a line of poetry. Syllables in dark boxes should be stressed.
- </p>
- <br>
<div id="entry"></div>
<div id="btns">
+ <div style="text-align: center;">
+ <div class="keyboard">
+ <div class="kbrow">
+ <div class="key" data-key="Q">Q</div>
+ <div class="key" data-key="W">W</div>
+ <div class="key" data-key="E">E</div>
+ <div class="key" data-key="R">R</div>
+ <div class="key" data-key="T">T</div>
+ <div class="key" data-key="Y">Y</div>
+ <div class="key" data-key="U">U</div>
+ <div class="key" data-key="I">I</div>
+ <div class="key" data-key="O">O</div>
+ <div class="key" data-key="P">P</div>
+ </div>
+ <div class="kbrow">
+ <div class="key" data-key="A">A</div>
+ <div class="key" data-key="S">S</div>
+ <div class="key" data-key="D">D</div>
+ <div class="key" data-key="F">F</div>
+ <div class="key" data-key="G">G</div>
+ <div class="key" data-key="H">H</div>
+ <div class="key" data-key="J">J</div>
+ <div class="key" data-key="K">K</div>
+ <div class="key" data-key="L">L</div>
+ <div class="key" data-key="Backspace">⇤</div>
+ </div>
+ <div class="kbrow">
+ <div class="key" data-key="Z">Z</div>
+ <div class="key" data-key="X">X</div>
+ <div class="key" data-key="C">C</div>
+ <div class="key" data-key="V">V</div>
+ <div class="key" data-key="B">B</div>
+ <div class="key" data-key="N">N</div>
+ <div class="key" data-key="M">M</div>
+ <div class="key" data-key="ArrowLeft">&larr;</div>
+ <div class="key" data-key="ArrowRight">&rarr;</div>
+ </div>
+ </div>
+ </div>
<button id="check" type="submit">Check</button>
<button id="clear">Clear</button>
</div>
- <br>
- <div style="text-align: center;">
- <div class="keyboard">
- <div class="kbrow">
- <div class="key" data-key="Q">Q</div>
- <div class="key" data-key="W">W</div>
- <div class="key" data-key="E">E</div>
- <div class="key" data-key="R">R</div>
- <div class="key" data-key="T">T</div>
- <div class="key" data-key="Y">Y</div>
- <div class="key" data-key="U">U</div>
- <div class="key" data-key="I">I</div>
- <div class="key" data-key="O">O</div>
- <div class="key" data-key="P">P</div>
- </div>
- <div class="kbrow">
- <div class="key" data-key="A">A</div>
- <div class="key" data-key="S">S</div>
- <div class="key" data-key="D">D</div>
- <div class="key" data-key="F">F</div>
- <div class="key" data-key="G">G</div>
- <div class="key" data-key="H">H</div>
- <div class="key" data-key="J">J</div>
- <div class="key" data-key="K">K</div>
- <div class="key" data-key="L">L</div>
- <div class="key" data-key="Backspace">⇤</div>
- </div>
- <div class="kbrow">
- <div class="key" data-key="Z">Z</div>
- <div class="key" data-key="X">X</div>
- <div class="key" data-key="C">C</div>
- <div class="key" data-key="V">V</div>
- <div class="key" data-key="B">B</div>
- <div class="key" data-key="N">N</div>
- <div class="key" data-key="M">M</div>
- <div class="key" data-key="ArrowLeft">&larr;</div>
- <div class="key" data-key="ArrowRight">&rarr;</div>
- </div>
- </div>
- </div>
<hr>
<div id="win" style="display: none;">
<p>
diff --git a/static/poems.js b/static/poems.js
index 89e8701..26ec581 100644
--- a/static/poems.js
+++ b/static/poems.js
@@ -1,6 +1,7 @@
var challenges = [
{
- "line": [["A"], ["/pre", "sence"], ["/that"], ["dis", "/turbs"], ["me"], ["/with"], ["the"], ["/joy"]],
+ "line": ["A", "presence", "that", "disturbs", "me", "with", "the", "joy"],
+ "scansion": ["x", "/x", "/", "x/", "x", "/", "x", "/"],
"title": "Lines written a few miles above Tintern Abbey",
"collection": "Lyrical Ballads",
"author": "William Wordsworth",
diff --git a/static/script.js b/static/script.js
index 7ed08db..caea216 100644
--- a/static/script.js
+++ b/static/script.js
@@ -4,40 +4,39 @@ var entryEl = document.getElementById("entry")
var guessesEl = document.getElementById("guesses")
var winEl = document.getElementById("win")
+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 = []
- 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'
+ 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'
- sylEls.push(`<div data-word="${wordIdx}" data-character="${c}" data-offset="${c+offset}" class="box ${typ} ${charclass}">${val}</div>`)
- c++;
}
-
- els.push(`<div class="syllable ` + stress + `">` + sylEls.join('') + `</div>`)
+ var val = guess ? guess[wordIdx][c] : ''
+ var typ = guess ? 'solbox' : 'entrybox'
+ els.push(`<div data-word="${wordIdx}" data-offset="${c+offset}" class="box ${typ} ${charclass}">${val}</div>`)
}
-
- return `<div class="word">` + els.join('') + `</div>`
+ var scansion = renderScansion(challenge.scansion[wordIdx])
+ var scansionBox = guess ? '' : `<div class="scansion-box"><span class="scansion">${scansion}</span></div>`
+ return `<div class="word">${scansionBox}${els.join('')}</div>`
}
function renderLine(line, guess, scores) {
@@ -46,7 +45,7 @@ function renderLine(line, guess, scores) {
for (var wordIdx in line) {
var word = line[wordIdx]
els.push(renderWord(word, wordIdx, guess, scores && scores[wordIdx], offset))
- offset += word.join('').replaceAll('/', '').length
+ offset += word.length
}
return `<div class="line">` + els.join('') + `</div>`
}
@@ -60,9 +59,9 @@ function consumeInput() {
}
els.sort((x, y) => {
var xword = x.getAttribute('data-word')
- var xchar = x.getAttribute('data-character')
+ var xchar = x.getAttribute('data-offset')
var yword = y.getAttribute('data-word')
- var ychar = y.getAttribute('data-character')
+ var ychar = y.getAttribute('data-offset')
if (xword != yword) {
return xword - yword;
@@ -81,8 +80,21 @@ 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))
+ var answerword = answer[idx].toUpperCase()
+ var score = scoreWord(guessword, answerword)
+ scores.push(score)
+ if (!information[idx]) {
+ information[idx] = {greens:{}, yellows:{}, greys:{}}
+ }
+ for (var i in score.greens) {
+ information[idx].greens[guessword[i]] = 1
+ }
+ 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
}
@@ -114,6 +126,37 @@ function scoreWord(guess, answer) {
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;
document.getElementById('clear').onclick = function(e) {
@@ -135,6 +178,7 @@ document.getElementById('check').addEventListener('click', function(e) {
var linehtml = renderLine(challenge.line, guess, 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;
@@ -182,12 +226,6 @@ function keyHandler(key) {
}
document.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;
- // }
if (e.ctrlKey || e.altKey || (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ".includes(e.key.toUpperCase()) && e.key != 'Backspace' && e.key != 'Enter' && e.key != 'ArrowLeft' && e.key != 'ArrowRight')) {
return;
}
@@ -211,7 +249,7 @@ document.addEventListener('mousedown', function(e) {
})
function getDailyChallenge() {
- // https://stackoverflow.com/a/8619946
+ // begin snippet from https://stackoverflow.com/a/8619946
var now = new Date();
var start = new Date(now.getFullYear(), 0, 0);
var diff = now - start;
@@ -230,6 +268,7 @@ document.getElementById('copy').addEventListener('click', function(e) {
function focus(el) {
focused = parseInt(el.getAttribute('data-offset'))
el.classList.add('focus')
+ renderKeyboardLights()
}
function unfocus(el) {
@@ -238,6 +277,7 @@ function unfocus(el) {
var guesses = []
+var information = {}
var challenge = getDailyChallenge()
entryEl.innerHTML = renderLine(challenge.line)
focus(document.querySelector(`[data-offset="0"]`));
diff --git a/static/styles.css b/static/styles.css
index 14d27d0..11a4cbb 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -1,85 +1,54 @@
-button {
- margin-right: 10px;
-}
-
.box {
display: inline-block;
- width: 25px;
- height: 25px;
+ width: 30px;
+ height: 30px;
text-align: center;
font-weight: bold;
- font-size: 14px;
- border: 2px lightgrey solid;
+ font-size: 18px;
+ border: 1px DarkSlateGrey solid;
margin-right: 0px;
margin-left: 0px;
color: black;
background-color: white;
vertical-align: top;
- line-height: 25px;
+ line-height: 29px;
font-family: Cantarell;
}
.focus {
- background-color: #fff079;
+ background-color: #ffda00
}
-.syllable .box:not(:first-child) {
+.word :not(:first-child) {
margin-left: -1px;
- border-left-style: dotted;
}
-.syllable .box:not(:last-child) {
+.word :not(:last-child) {
margin-right: -1px;
- border-right-style: dotted;
-}
-
-.word .syllable:not(:first-child) {
- margin-left: -1px;
-}
-
-.word .syllable:not(:last-child) {
- margin-right: -1px;
-}
-
-.syllable.stress + .syllable .entrybox:first-child {
- border-left-color: darkslategrey;
-}
-
-.stress {
- z-index: 9999;
}
-.syllable {
- display: inline-block;
-}
-.syllable-sep {
- display: inline-block;
- font-size: 30px;
- margin: 1px;
-}
.word {
display: inline-block;
- margin-right: 40px;
+ margin-right: 20px;
margin-bottom: 5px;
}
+
.line {
margin-bottom: 15px;
}
-.stress>.entrybox {
- border-color: darkslategrey;
-}
-
.green {
background-color: rgb(106, 170, 100);
color: white;
border-color: rgb(106, 170, 100);
}
+
.yellow {
background-color: rgb(201, 180, 88);
color: white;
border-color: rgb(201,180,88);
}
+
.grey {
background-color: rgb(120, 124, 126);
color: white;
@@ -113,11 +82,6 @@ hr {
}
@media only screen and (min-width: 600px) {
- .keyboard {
- border: 1px darkslategrey dotted;
- border-radius: 4px;
- padding: 1.2em;
- }
form {
border: 1px DarkSlateGrey solid;
padding: 1em;
@@ -136,8 +100,42 @@ hr {
height: 35px;
width: 26px;
border-radius: 4px;
- border: 1px black solid;
+ border: 1px black dotted;
line-height: 33px;
cursor: pointer;
user-select: none;
}
+.key:hover{
+ border-style:solid;
+}
+
+.greenkey {
+ background-color: rgb(106, 170, 100);
+ color: white;
+ border-color: rgb(106, 170, 100);
+}
+
+.yellowkey {
+ background-color: rgb(201, 180, 88);
+ color: white;
+ border-color: rgb(201,180,88);
+}
+
+.greykey {
+ background-color: rgb(120, 124, 126);
+ color: white;
+ border-color: rgb(120,124,126);
+}
+}
+
+/* .key:hover { */
+/* background-color: #f7edd6; */
+/* } */
+
+.scansion {
+ font-size: 90%;
+}
+
+.scansion-box {
+ margin-bottom: .3em;
+}