summaryrefslogtreecommitdiff
path: root/pub
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-09-18 12:44:49 -0400
committerpommicket <pommicket@gmail.com>2025-09-18 12:44:49 -0400
commit7e359e4c8888c0630c4c7dda709b3fc041a18235 (patch)
tree6dd12931ccf6dd1c6d699cdd2680bb47925e4ceb /pub
parentc728aae2527221032f47fded2fb697d95661977d (diff)
Show solutions
Diffstat (limited to 'pub')
-rw-r--r--pub/blankplays.js178
-rw-r--r--pub/index.html21
2 files changed, 167 insertions, 32 deletions
diff --git a/pub/blankplays.js b/pub/blankplays.js
index e58a4b2..d15bb81 100644
--- a/pub/blankplays.js
+++ b/pub/blankplays.js
@@ -5,15 +5,15 @@ const N = 15; // board size
let lexicon = 'nwl23';
function updateBoardSize() {
- let board = document.getElementById('board');
+ let boardElem = document.getElementById('board');
// sucks for desktop zooming, but there's no way around it.
let width = innerWidth;
let height = innerHeight;
let boardSize = Math.min(width - 20, Math.floor(height * 0.6));
let fontSize = (boardSize / N - 4) * 0.6;
- board.style.fontSize = fontSize + 'px';
- board.style.width = boardSize + 'px';
- board.style.height = boardSize + 'px';
+ boardElem.style.fontSize = fontSize + 'px';
+ boardElem.style.width = boardSize + 'px';
+ boardElem.style.height = boardSize + 'px';
let selectContainer = document.getElementById('select-container');
selectContainer.style.fontSize = fontSize + 'px';
selectContainer.style.width = boardSize + 'px';
@@ -55,18 +55,26 @@ function pointValue(letter) {
let boardSquareElems = [];
let currSolution = [];
+let board = [];
+let trueSolution = [];
+let skipWordsOfLength = 1;
+let alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
-function updatePossibilities(highlightElem, letters) {
- let possibilitiesElem = highlightElem.querySelector('.possibilities');
- possibilitiesElem.innerText = letters.join('');
- let n = letters.length;
- let fontSize = n === 1 ? 100
+function getFontSizeForPossibilities(n) {
+ return (n === 1 ? 100
: n < 5 ? 60
: n < 7 ? 48
: n < 12 ? 40
: n < 20 ? 32
- : 26;
- possibilitiesElem.style.fontSize = fontSize + '%';
+ : 26) + '%';
+}
+
+function updatePossibilities(highlightElem, letters) {
+ let possibilitiesElem = highlightElem.querySelector('.possibilities');
+ possibilitiesElem.innerText = letters.join('');
+ let n = letters.length;
+ let fontSize = getFontSizeForPossibilities(n);
+ possibilitiesElem.style.fontSize = fontSize;
}
function addToSolution(row, col, letter) {
@@ -173,12 +181,29 @@ function clickedSquare(highlight, row, col) {
};
}
+function includeSquare(row, col) {
+ if (board[row][col] !== '.') return false;
+ let neighbours = [];
+ if (row > 0)
+ neighbours.push(board[row-1][col]);
+ if (row < N-1)
+ neighbours.push(board[row+1][col]);
+ if (col > 0)
+ neighbours.push(board[row][col-1]);
+ if (col < N-1)
+ neighbours.push(board[row][col+1]);
+ if (neighbours.filter((x) => x !== '.').length === 0) {
+ // not connected
+ return false;
+ }
+ return true;
+}
+
// TODO : error handling
async function loadChallenge(id) {
let result = await fetch(`challenges-${lexicon}/${id}.txt`);
let body = await result.text();
let lines = body.split('\n');
- let board = [];
for (let row = 0; row < 15; row++) {
board.push([]);
for (let col = 0; col < 15; col++) {
@@ -186,25 +211,33 @@ async function loadChallenge(id) {
}
}
for (let row = 0; row < 15; row++) {
+ trueSolution.push([]);
+ for (let col = 0; col < 15; col++) {
+ trueSolution[row].push([]);
+ }
+ }
+ for (let i = 15; i < lines.length; i++) {
+ if (!lines[i]) continue;
+ let parts = lines[i].split(' ');
+ let square = parseInt(parts[0]);
+ let letter = parts[1];
+ trueSolution[Math.floor(square / 15)][square % 15].push(letter);
+ }
+ for (let row = 0; row < 15; row++)
+ for (let col = 0; col < 15; col++)
+ trueSolution[row][col].sort();
+ for (let highlight of document.querySelectorAll('.highlight')) {
+ highlight.remove();
+ }
+ for (let row = 0; row < 15; row++) {
for (let col = 0; col < 15; col++) {
let letter = board[row][col];
if (letter !== '.') {
putTile(row, col, letter);
continue;
}
- let neighbours = [];
- if (row > 0)
- neighbours.push(board[row-1][col]);
- if (row < N-1)
- neighbours.push(board[row+1][col]);
- if (col > 0)
- neighbours.push(board[row][col-1]);
- if (col < N-1)
- neighbours.push(board[row][col+1]);
- if (neighbours.filter((x) => x !== '.').length === 0) {
- // not connected
+ if (!includeSquare(row, col))
continue;
- }
let highlight = document.createElement('div');
highlight.classList.add('highlight');
highlight.dataset.row = row;
@@ -212,19 +245,102 @@ async function loadChallenge(id) {
let possibilities = document.createElement('span');
possibilities.classList.add('possibilities');
highlight.appendChild(possibilities);
+ updatePossibilities(highlight, currSolution[row][col]);
boardSquareElems[row][col].appendChild(highlight);
highlight.addEventListener('contextmenu', (e) => e.preventDefault());
highlight.addEventListener('mousedown', clickedSquare(highlight, row, col));
}
}
+ updateSkipWordsOfLength();
+}
+
+function updateSkipWordsOfLength() {
+ let skip2s = document.getElementById('skip-2s');
+ let skip3s = document.getElementById('skip-3s');
+ skipWordsOfLength = skip3s.checked ? 3 : skip2s.checked ? 2 : 1;
+ for (let row = 0; row < 15; row++) {
+ for (let col = 0; col < 15; col++) {
+ if (!includeSquare(row, col)) continue;
+ let i = row;
+ while (i > 0 && board[i-1][col] !== '.')
+ i -= 1;
+ let verticalWordLen = 1;
+ while (i < N-1 && (i+1 === row || board[i+1][col] !== '.')) {
+ verticalWordLen += 1;
+ i += 1;
+ }
+ i = col;
+ let horizontalWordLen = 1;
+ while (i > 0 && board[row][i-1] !== '.')
+ i -= 1;
+ while (i < N-1 && (i+1 === col || board[row][i+1] !== '.')) {
+ horizontalWordLen += 1;
+ i += 1;
+ }
+ let tooShort = Math.max(horizontalWordLen, verticalWordLen) <= skipWordsOfLength;
+ document.querySelector(`.highlight[data-row="${row}"][data-col="${col}"]`).style.visibility =
+ tooShort ? 'hidden' : 'visible';
+ }
+ }
+}
+
+function showSolution() {
+ document.getElementById('select').style.display = 'none';
+ document.getElementById('place').style.display = 'none';
+ for (let row = 0; row < 15; row++) {
+ for (let col = 0; col < 15; col++) {
+ if (!includeSquare(row, col))
+ continue;
+ let guess = currSolution[row][col];
+ let solution = trueSolution[row][col];
+ let possibilitiesElem = document.querySelector(`[data-row="${row}"][data-col="${col}"] .possibilities`);
+ possibilitiesElem.innerHTML = '';
+ let totalLength = 0;
+ for (let letter of alphabet) {
+ let inGuess = guess.indexOf(letter) !== -1;
+ let inSolution = solution.indexOf(letter) !== -1;
+ if (!inGuess && !inSolution) continue;
+ let span = document.createElement('span');
+ span.innerText = letter;
+ totalLength += letter.length;
+ span.classList.add('solution-letter');
+ if (!inGuess && inSolution) {
+ span.classList.add('missed');
+ } else if (inGuess && !inSolution) {
+ span.classList.add('wrong');
+ } else {
+ span.classList.add('correct');
+ }
+ possibilitiesElem.appendChild(span);
+ }
+ let fontSize = getFontSizeForPossibilities(totalLength);
+ possibilitiesElem.style.fontSize = fontSize;
+ }
+ }
}
function startup() {
+ let boardElem = document.getElementById('board');
+ let skip2s = document.getElementById('skip-2s');
+ let skip3s = document.getElementById('skip-3s');
+ skip2s.addEventListener('change', () => {
+ if (!skip2s.checked)
+ skip3s.checked = false;
+ updateSkipWordsOfLength();
+ });
+ skip3s.addEventListener('change', () => {
+ if (skip3s.checked)
+ skip2s.checked = true;
+ updateSkipWordsOfLength();
+ });
+ document.getElementById('submit').addEventListener('click', () => {
+ showSolution();
+ });
updateBoardSize();
for (let row = 0; row < N; row++) {
let rowElem = document.createElement('div');
rowElem.classList.add('board-row');
- board.appendChild(rowElem);
+ boardElem.appendChild(rowElem);
boardSquareElems.push([]);
currSolution.push([]);
for (let col = 0; col < N; col++) {
@@ -241,13 +357,13 @@ function startup() {
for (let row = 0; row < 2; row++) {
let rowContainer = selectContainer.querySelectorAll('.select-container-row')[row];
for (let i = row*N; i < (row+1)*N; i++) {
- let tiles = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
- if (i >= tiles.length) break;
+ if (i >= alphabet.length) break;
let elem = document.createElement('span');
elem.classList.add('select-tile-container');
- makeTile(elem, tiles[i], false);
+ let letter = alphabet[i];
+ makeTile(elem, letter, false);
let tileElem = elem.querySelector('.tile');
- tileElem.dataset.letter = tiles[i];
+ tileElem.dataset.letter = letter;
elem.addEventListener('click', () => {
let tileSelected = document.querySelector('.highlight.selected');
let className = tileSelected ? 'possible' : 'placing';
@@ -256,7 +372,7 @@ function startup() {
if (tileSelected) {
let row = parseInt(tileSelected.dataset.row);
let col = parseInt(tileSelected.dataset.col);
- removeFromSolution(row, col, tiles[i]);
+ removeFromSolution(row, col, letter);
}
} else {
let placing = document.querySelector('.placing');
@@ -265,7 +381,7 @@ function startup() {
if (tileSelected) {
let row = parseInt(tileSelected.dataset.row);
let col = parseInt(tileSelected.dataset.col);
- addToSolution(row, col, tiles[i]);
+ addToSolution(row, col, letter);
}
}
});
diff --git a/pub/index.html b/pub/index.html
index aead4de..5b6236a 100644
--- a/pub/index.html
+++ b/pub/index.html
@@ -110,12 +110,31 @@
background-color: #88c;
font-weight: bold;
}
+ #submit {
+ outline: 0;
+ border: 2px solid #44a;
+ outline: 2px solid #00a;
+ box-shadow: 2px 2px 4px #00a;
+ margin: 4px;
+ border-radius: 5px;
+ padding: 2px 5px;
+ background: #ddf;
+ }
+ #submit:hover {
+ background: #bbf;
+ }
+ #submit:active {
+ transform: translate(2px, 2px);
+ box-shadow: 0 0 0;
+ }
</style>
<script src="/blankplays.js" async></script>
</head>
<body>
Find all the possible plays with a single blank!<br>
- <button>All done!</button>
+ <label><input type="checkbox" id="skip-2s"> Skip 2’s</label>
+ <label><input type="checkbox" id="skip-3s"> Skip 3’s</label>
+ <button id="submit">All done!</button>
<div id="board"></div>
<div id="select" style="display: none;">
Select which letters can go here: