summaryrefslogtreecommitdiff
path: root/pub
diff options
context:
space:
mode:
Diffstat (limited to 'pub')
-rw-r--r--pub/blankplays.js172
-rw-r--r--pub/index.css167
-rw-r--r--pub/index.html13
3 files changed, 229 insertions, 123 deletions
diff --git a/pub/blankplays.js b/pub/blankplays.js
index ff964e2..e58b9e3 100644
--- a/pub/blankplays.js
+++ b/pub/blankplays.js
@@ -25,8 +25,7 @@ function updateBoardSize() {
boardElem.style.height = boardSize + 'px';
let selectContainer = document.getElementById('select-container');
selectContainer.style.fontSize = fontSize;
- selectContainer.style.width = boardSize + 'px';
- selectContainer.style.height = boardSize / N * 2 + 'px';
+ selectContainer.style.maxWidth = boardSize + 'px';
}
const DOUBLE_LETTER = 'double-letter';
@@ -79,10 +78,14 @@ function loadAttempt() {
// old data
return;
}
- for (let row = 0; row < 15; row++) {
- for (let col = 0; col < 15; col++) {
+ for (let row = 0; row < N; row++) {
+ for (let col = 0; col < N; col++) {
for (let letter of saveData.solution[row][col]) {
- addToSolution(row, col, letter);
+ addToGuesses(row, col, letter);
+ }
+ if (saveData.eliminated && saveData.eliminated[row*N+col]) {
+ document.querySelector(`.highlight[data-row="${row}"][data-col="${col}"]`)
+ .classList.add('nothing');
}
}
}
@@ -91,11 +94,18 @@ function loadAttempt() {
}
function saveAttempt() {
+ let eliminated = new Array(N*N).fill(false);
+ for (let highlightElem of document.querySelectorAll('.highlight.nothing')) {
+ let row = parseInt(highlightElem.dataset.row);
+ let col = parseInt(highlightElem.dataset.col);
+ eliminated[row*N+col] = true;
+ }
let saveData = {
version: 1,
id: challengeId,
solution: currAttempt,
finished: finished,
+ eliminated: eliminated,
};
localStorage.setItem(`attempt-${lexicon}`, JSON.stringify(saveData));
}
@@ -118,7 +128,7 @@ function updatePossibilities(highlightElem, letters) {
possibilitiesElem.style.fontSize = fontSize;
}
-function addToSolution(row, col, letter) {
+function addToGuesses(row, col, letter) {
let highlight = document.querySelector(`.highlight[data-row="${row}"][data-col="${col}"]`);
if (letter === NOTHING) {
currAttempt[row][col] = [];
@@ -136,7 +146,7 @@ function addToSolution(row, col, letter) {
saveAttempt();
}
-function removeFromSolution(row, col, letter) {
+function removeFromGuesses(row, col, letter) {
let highlight = document.querySelector(`.highlight[data-row="${row}"][data-col="${col}"]`);
if (letter === NOTHING) {
highlight.classList.remove('nothing');
@@ -150,13 +160,20 @@ function removeFromSolution(row, col, letter) {
saveAttempt();
}
-function toggleInSolution(row, col, letter) {
- let letters = currAttempt[row][col];
- let idx = letters.indexOf(letter);
- if (idx === -1) {
- addToSolution(row, col, letter);
+function toggleInGuesses(row, col, letter) {
+ let currentlyContains;
+ if (letter === NOTHING) {
+ let highlight = document.querySelector(`.highlight[data-row="${row}"][data-col="${col}"]`);
+ currentlyContains = highlight.classList.contains('nothing');
+ } else {
+ let letters = currAttempt[row][col].slice();
+ let idx = letters.indexOf(letter);
+ currentlyContains = idx !== -1;
+ }
+ if (currentlyContains) {
+ removeFromGuesses(row, col, letter);
} else {
- removeFromSolution(row, col, letter);
+ addToGuesses(row, col, letter);
}
}
@@ -187,7 +204,7 @@ function putTile(row, col, letter) {
function selectTile(elem, row, col) {
deselectTile();
- document.getElementById('select-container').style.display = 'grid';
+ document.getElementById('select-container').style.display = 'block';
let placing = document.querySelector('.tile.placing');
if (placing)
placing.classList.remove('placing');
@@ -250,7 +267,7 @@ function clickedSquare(highlight, row, col) {
if (e.button === 0) {
let placing = document.querySelector('.placing');
if (placing) {
- toggleInSolution(row, col, placing.dataset.letter);
+ toggleInGuesses(row, col, placing.dataset.letter);
} else if (highlight.classList.contains('selected')) {
deselectTile();
} else {
@@ -264,6 +281,7 @@ function clickedSquare(highlight, row, col) {
highlight.classList.add('nothing');
if (highlight.classList.contains('selected'))
deselectTile();
+ saveAttempt();
}
e.preventDefault();
}
@@ -300,32 +318,31 @@ Please e-mail ${EMAIL}`);
Try refreshing the page, or clearing your browser's cache for this site.
If problem persists, e-mail ${EMAIL}.`);
}
- // TODO : check format & report error if wrong
let body = await result.text();
let lines = body.split('\n');
board = [];
- for (let row = 0; row < 15; row++) {
+ for (let row = 0; row < N; row++) {
board.push([]);
- for (let col = 0; col < 15; col++) {
+ for (let col = 0; col < N; col++) {
board[row].push(lines[row][col]);
}
}
trueSolution = [];
- for (let row = 0; row < 15; row++) {
+ for (let row = 0; row < N; row++) {
trueSolution.push([]);
- for (let col = 0; col < 15; col++) {
+ for (let col = 0; col < N; col++) {
trueSolution[row].push([]);
}
}
- for (let i = 15; i < lines.length; i++) {
+ for (let i = N; i < lines.length; i++) {
if (!lines[i]) continue;
let parts = lines[i].split(' ');
let square = parseInt(parts[0], 10);
let letter = parts[1];
- trueSolution[Math.floor(square / 15)][square % 15].push(letter);
+ trueSolution[Math.floor(square / N)][square % N].push(letter);
}
- for (let row = 0; row < 15; row++)
- for (let col = 0; col < 15; col++)
+ for (let row = 0; row < N; row++)
+ for (let col = 0; col < N; col++)
trueSolution[row][col].sort();
updateBoard();
loadAttempt();
@@ -336,8 +353,8 @@ function updateBoard() {
for (let highlight of document.querySelectorAll('.highlight')) {
highlight.remove();
}
- for (let row = 0; row < 15; row++) {
- for (let col = 0; col < 15; col++) {
+ for (let row = 0; row < N; row++) {
+ for (let col = 0; col < N; col++) {
let letter = board[row][col];
if (letter !== '.') {
putTile(row, col, letter);
@@ -387,8 +404,8 @@ function updateSkipWordsOfLength() {
let skip4s = document.getElementById('skip-4s');
skipWordsOfLength = skip4s.checked ? 4 : skip3s.checked ? 3 : skip2s.checked ? 2 : 1;
localStorage.setItem(`skip-${lexicon}`, skipWordsOfLength);
- for (let row = 0; row < 15; row++) {
- for (let col = 0; col < 15; col++) {
+ for (let row = 0; row < N; row++) {
+ for (let col = 0; col < N; col++) {
if (!includeSquare(row, col)) continue;
let tooShort = skipDueToLength(row, col);
document.querySelector(`.highlight[data-row="${row}"][data-col="${col}"]`).style.visibility =
@@ -409,8 +426,8 @@ function showSolution() {
let correctPlays = 0;
let incorrectPlays = 0;
let missedPlays = 0;
- for (let row = 0; row < 15; row++) {
- for (let col = 0; col < 15; col++) {
+ for (let row = 0; row < N; row++) {
+ for (let col = 0; col < N; col++) {
if (!includeSquare(row, col))
continue;
let guess = currAttempt[row][col];
@@ -465,14 +482,15 @@ function showSolution() {
// stop rounding to 100 when not perfect
score = Math.min(score, 99);
}
+ let statsElem = document.getElementById('stats');
+ statsElem.style.setProperty('--score-color', `hsl(${Math.round(score*120/100)}deg 90% 30%)`);
let scoreMeter = document.getElementById('score-meter');
scoreMeter.value = score;
- scoreMeter.style.setProperty('--color', `hsl(${Math.round(score*120/100)}deg 90% 50%)`);
document.getElementById('score-span').innerText = score;
document.getElementById('correct-plays').innerText = correctPlays;
document.getElementById('incorrect-plays').innerText = incorrectPlays;
document.getElementById('missed-plays').innerText = missedPlays;
- document.getElementById('stats').style.display = 'block';
+ statsElem.style.display = 'block';
let shareText = `I scored ${score}/100 on today's BlankPlays!`;
if (score === 100)
shareText += ' 😎';
@@ -517,6 +535,24 @@ function startup() {
document.getElementById('report-issue-button').addEventListener('click', () => {
showDialogById('report-issue');
});
+ let darkModeButton = document.getElementById('dark-mode');
+ let lightModeButton = document.getElementById('light-mode');
+ if (window.darkMode) // set in inline script
+ darkModeButton.checked = true;
+ else
+ lightModeButton.checked = true;
+ darkModeButton.addEventListener('change', () => {
+ if (darkModeButton.checked) {
+ document.body.classList.add('dark-mode');
+ localStorage.setItem('color-mode', 'dark');
+ }
+ });
+ lightModeButton.addEventListener('change', () => {
+ if (lightModeButton.checked) {
+ document.body.classList.remove('dark-mode');
+ localStorage.setItem('color-mode', 'light');
+ }
+ });
let lexiconSelect = document.getElementById('lexicon');
lexiconSelect.value = lexicon;
lexiconSelect.addEventListener('change', () => {
@@ -571,46 +607,40 @@ function startup() {
let selectContainer = document.getElementById('select-container');
let selections = alphabet.slice();
selections.push(NOTHING);
- for (let tileRow = 0; tileRow * N < selections.length; tileRow++) {
- let rowContainer = document.createElement('div');
- rowContainer.classList.add('select-container-row');
- selectContainer.appendChild(rowContainer);
- for (let i = tileRow*N; i < (tileRow+1)*N; i++) {
- if (i >= selections.length) break;
- let letter = selections[i];
- let elem = document.createElement('span');
- elem.classList.add('select-tile-container');
- if (letter === NOTHING) {
- elem.id = 'select-nothing';
- }
- makeTile(elem, letter, false);
- let tileElem = elem.querySelector('.tile');
- tileElem.dataset.letter = letter;
- elem.addEventListener('click', () => {
- if (finished) return;
- let tileSelected = document.querySelector('.highlight.selected');
- let className = !tileSelected ? 'placing' :
- letter === NOTHING ? '__unused' : 'possible';
- if (tileElem.classList.contains(className)) {
- tileElem.classList.remove(className);
- if (tileSelected) {
- let row = parseInt(tileSelected.dataset.row);
- let col = parseInt(tileSelected.dataset.col);
- removeFromSolution(row, col, letter);
- }
- } else {
- let placing = document.querySelector('.placing');
- if (placing) placing.classList.remove('placing');
- tileElem.classList.add(className);
- if (tileSelected) {
- let row = parseInt(tileSelected.dataset.row);
- let col = parseInt(tileSelected.dataset.col);
- addToSolution(row, col, letter);
- }
- }
- });
- rowContainer.appendChild(elem);
+ for (let i = 0; i < selections.length; i++) {
+ let letter = selections[i];
+ let elem = document.createElement('span');
+ elem.classList.add('select-tile-container');
+ if (letter === NOTHING) {
+ elem.id = 'select-nothing';
}
+ makeTile(elem, letter, false);
+ let tileElem = elem.querySelector('.tile');
+ tileElem.dataset.letter = letter;
+ elem.addEventListener('click', () => {
+ if (finished) return;
+ let tileSelected = document.querySelector('.highlight.selected');
+ let className = !tileSelected ? 'placing' :
+ letter === NOTHING ? '__unused' : 'possible';
+ if (tileElem.classList.contains(className)) {
+ tileElem.classList.remove(className);
+ if (tileSelected) {
+ let row = parseInt(tileSelected.dataset.row);
+ let col = parseInt(tileSelected.dataset.col);
+ removeFromGuesses(row, col, letter);
+ }
+ } else {
+ let placing = document.querySelector('.placing');
+ if (placing) placing.classList.remove('placing');
+ tileElem.classList.add(className);
+ if (tileSelected) {
+ let row = parseInt(tileSelected.dataset.row);
+ let col = parseInt(tileSelected.dataset.col);
+ addToGuesses(row, col, letter);
+ }
+ }
+ });
+ selectContainer.appendChild(elem);
}
loadChallenge('00000');
}
diff --git a/pub/index.css b/pub/index.css
index 7928e00..840cae3 100644
--- a/pub/index.css
+++ b/pub/index.css
@@ -1,10 +1,74 @@
body {
font-family: Helvetica, sans-serif;
--tile-margin: 5%;
+ --tile-color: #eca;
+ --button-background-color: #eee;
+ --button-outline-color: #333;
+ --hl-nothing-color: #f00;
+ --hl-selected-color: #00f;
+ --hl-border-color: rgba(60,60,60,0.6);
+ --hl-all-correct-color: #0a0;
+ --hl-some-mistakes-color: #f80;
+ --square-color: #dde;
+ --double-letter-color: #acf;
+ --triple-letter-color: #afc;
+ --double-word-color: #fac;
+ --triple-word-color: #c66;
+ --select-tile-border-color: black;
+ --select-tile-possible-color: #8c7;
+ --select-tile-placing-color: #aff;
+ --select-tile-not-possible-color: #d99;
+ --submit-outline-color: #00a;
+ --submit-border-color: #55a;
+ --submit-background-color: #ddf;
+ --submit-hover-color: #bbf;
+ --solution-letter-wrong-color: #800;
+ --solution-letter-correct-color: #060;
+ --solution-letter-missed-color: #00a;
+}
+body.dark-mode {
+ background-color: #112;
+ color: #f8f8f8;
+ --square-color: #445;
+ --tile-color: #520;
+ --button-outline-color: #ccc;
+ --button-background-color: #223;
+ --hl-border-color: rgba(200,200,200,0.4);
+ --hl-selected-color: #0ff;
+ --double-letter-color: #569;
+ --triple-letter-color: #465;
+ --double-word-color: #525;
+ --triple-word-color: #822;
+ --select-tile-border-color: #ccc;
+ --select-tile-possible-color: #272;
+ --select-tile-placing-color: #466;
+ --submit-outline-color: #8fc;
+ --submit-border-color: #5ac;
+ --submit-background-color: #266;
+ --submit-hover-color: #488;
+ --solution-letter-wrong-color: #faa;
+ --solution-letter-correct-color: #afa;
+ --solution-letter-missed-color: #9ff;
+}
+.dark-mode a {
+ color: #afc;
+}
+.dark-mode textarea {
+ background-color: transparent;
+ border: 2px solid #fff;
+ color: inherit;
+}
+button {
+ color: inherit;
+ background-color: var(--button-background-color);
+ outline: 2px solid var(--button-outline-color);
+ border: 0;
+ border-radius: 2px;
+ margin: 6px;
}
/* use minimal margins on small screens,
to maximize available space for board. */
-@media (width < 10cm) {
+@media (width < 15cm) {
body {
margin: 2px;
--tile-margin: 0%;
@@ -21,24 +85,24 @@ body {
}
.board-square {
margin: 1px;
- background-color: #dde;
+ background-color: var(--square-color);
line-height: 1;
position: relative;
}
.board-square.double-letter {
- background-color: #acf;
+ background-color: var(--double-letter-color);
}
.board-square.triple-letter {
- background-color: #afc;
+ background-color: var(--triple-letter-color);
}
.board-square.double-word {
- background-color: #fac;
+ background-color: var(--double-word-color);
}
.board-square.triple-word {
- background-color: #c66;
+ background-color: var(--triple-word-color);
}
.tile {
- background: #eca;
+ background-color: var(--tile-color);
position: absolute;
width: calc(100% - 2 * var(--tile-margin));
height: calc(100% - 2 * var(--tile-margin));
@@ -51,11 +115,10 @@ body {
font-weight: bold;
}
.blank {
- color: #333;
font-weight: normal;
}
.highlight {
- border: min(0.5vw,0.5vh) solid rgba(60,60,60,0.6);
+ border: 0.5vmin solid var(--hl-border-color);
width: 100%;
height: 100%;
box-sizing: border-box;
@@ -65,17 +128,20 @@ body {
justify-content: center;
align-items: center;
}
+input[name=color-mode] {
+ margin-left: 0.5em;
+}
.highlight.nothing {
- border-color: #f00;
+ border-color: var(--hl-nothing-color);
}
#board .highlight.selected {
- border-color: #00f;
+ border-color: var(--hl-selected-color);
}
.highlight.all-correct {
- border-color: #0a0;
+ border-color: var(--hl-all-correct-color);
}
.highlight.some-mistakes {
- border-color: #f80;
+ border-color: var(--hl-some-mistakes-color);
}
.possibilities {
word-break: break-all;
@@ -93,59 +159,56 @@ body {
font-size: 30%;
}
#select-container {
- display: grid;
- grid-template-rows: repeat(2, 1fr);
-}
-.select-container-row {
- display: grid;
- grid-template-columns: repeat(15, 1fr);
- grid-auto-flow: column;
width: 100%;
}
.select-tile-container {
- position: relative;
cursor: pointer;
- margin: 2px;
}
.select-tile-container .tile {
+ position: static;
+ display: inline-flex;
background-color: transparent;
font-weight: normal;
- border: 2px solid black;
+ box-sizing: border-box;
+ border: 0.3vmin solid var(--select-tile-border-color);
+ width: min(1.5cm,10vmin);
+ height: min(1.5cm,10vmin);
+ font-size: min(1.2cm,8vmin);
+ margin: 2px;
}
.select-tile-container .tile.possible,
.select-tile-container .tile.correct {
- background-color: #8c7;
+ background-color: var(--select-tile-possible-color);
font-weight: bold;
- text-decoration: underline;
+ border-width: 0.6vmin;
}
.select-tile-container .tile.missed {
- background-color: #8c7;
+ background-color: var(--select-tile-possible-color);
}
.select-tile-container .tile.not-possible {
- background-color: #c88;
+ background-color: var(--select-tile-not-possible-color);
}
.select-tile-container .tile.wrong {
- background-color: #c88;
+ background-color: var(--select-tile-not-possible-color);
font-weight: bold;
- text-decoration: underline;
+ border-width: 0.6vmin;
}
.select-tile-container .tile.placing {
- background-color: #88c;
+ background-color: var(--select-tile-placing-color);
font-weight: bold;
- text-decoration: underline;
}
#submit {
outline: 0;
- border: 2px solid #44a;
- outline: 2px solid #00a;
- box-shadow: 2px 2px 4px #00a;
- margin: 4px;
+ border: 2px solid var(--submit-border-color);
+ outline: 2px solid var(--submit-outline-color);
+ box-shadow: 2px 2px 4px var(--submit-outline-color);
+ margin-bottom: 1.5em;
border-radius: 5px;
- padding: 2px 5px;
- background: #ddf;
+ padding: 4px 8px;
+ background: var(--submit-background-color);
}
#submit:hover {
- background: #bbf;
+ background: var(--submit-hover-color);
}
#submit:active {
transform: translate(2px, 2px);
@@ -154,18 +217,13 @@ body {
.solution-letter.wrong {
text-decoration: line-through;
font-weight: bold;
- color: #800;
-}
-.solution-letter.wrong {
- text-decoration: line-through;
- font-weight: bold;
- color: #800;
+ color: var(--solution-letter-wrong-color);
}
.solution-letter.correct {
- color: #060;
+ color: var(--solution-letter-correct-color);
}
.solution-letter.missed {
- color: #00a;
+ color: var(--solution-letter-missed-color);
font-weight: bold;
}
/* all browsers which support grid should support
@@ -175,9 +233,13 @@ body {
display: none;
}
}
-progress#score-meter::-moz-progress-bar { background: var(--color); }
-progress#score-meter::-webkit-progress-value { background: var(--color); }
-progress#score-meter { color: var(--color); }
+progress#score-meter::-moz-progress-bar { background: var(--score-color); }
+progress#score-meter::-webkit-progress-value { background: var(--score-color); }
+progress#score-meter { color: var(--score-color); }
+#score-ratio {
+ color: var(--score-color);
+ font-weight: bold;
+}
h2, h3 {
margin: 2px;
}
@@ -187,10 +249,13 @@ h2, h3 {
line-height: 1;
}
dialog {
- max-width: 50em;
+ max-width: min(50em,80%);
+ /* weirdness for the sake of old browsers (with no <dialog>) */
display: none;
}
dialog[open] {
- max-width: 50em;
display: block;
}
+textarea {
+ max-width: 90%;
+}
diff --git a/pub/index.html b/pub/index.html
index d79521b..8f26796 100644
--- a/pub/index.html
+++ b/pub/index.html
@@ -9,6 +9,15 @@
<script src="/blankplays.js" async></script>
</head>
<body>
+ <script blocking="render">
+ // this is a separate inline script to prevent a
+ // light-mode flash when loading the page
+ window.darkMode = localStorage.getItem('color-mode') === 'dark'
+ || (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
+ if (window.darkMode) {
+ document.body.classList.add('dark-mode');
+ }
+ </script>
<noscript>
<b>You must enable JavaScript in your browser to do these puzzles.</b><br>
</noscript>
@@ -31,6 +40,8 @@
<label><input type="checkbox" id="skip-2s"> Skip 2’s</label>
<label><input type="checkbox" id="skip-3s"> Skip 3’s</label>
<label><input type="checkbox" id="skip-4s"> Skip 4’s</label>
+ <label><input type="radio" name="color-mode" id="light-mode">☀️ Light</label>
+ <label><input type="radio" name="color-mode" id="dark-mode">🌙 Dark</label>
<button id="submit">All done!</button>
<div id="board"></div>
<div id="select-heading" style="display: none;">
@@ -42,7 +53,7 @@
<div id="select-container"></div>
<div id="stats" style="display:none;">
Score: <progress id="score-meter" max="100"></progress>
- <span id="score-span"></span>/100<br>
+ <span id="score-ratio"><span id="score-span"></span>/100</span><br>
Correct plays identified: <span id="correct-plays"></span><br>
Incorrect plays guessed: <span id="incorrect-plays"></span><br>
Missed plays: <span id="missed-plays"></span><br>