diff options
Diffstat (limited to 'pub')
-rw-r--r-- | pub/blankplays.js | 172 | ||||
-rw-r--r-- | pub/index.css | 167 | ||||
-rw-r--r-- | pub/index.html | 13 |
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> |