For the past 3 years, my brain has been wired to:
npx create-vite@latest-
useState,useEffect,useCallback - components inside components inside components
So when I decided to build a crossword puzzle solver the "vanilla way" โ no framework, no JSX, no hot reload โ I felt naked.
But here we are. With raw 2D arrays, nested loops, and the humbling realization that I still struggle with grid[r][c+len].
The Slots Extractor (I'm actually proud of this)
function extractSlots(grid) {
const slots = [];
for (let r = 0; r < grid.length; r++) {
for (let c = 0; c < grid[0].length; c++) {
if (grid[r][c] === '.') continue;
// Across word?
if (c === 0 || grid[r][c-1] === '.') {
let len = 0;
while (grid[r][c+len] && grid[r][c+len] !== '.') len++;
if (len > 1) slots.push({row:r, col:c, len, dir:'across'});
}
// Down word?
if (r === 0 || grid[r-1][c] === '.') {
let len = 0;
while (grid[r+len] && grid[r+len][c] !== '.') len++;
if (len > 1) slots.push({row:r, col:c, len, dir:'down'});
}
}
}
return slots;
}
The Embarrassing Bug I Spent 2 Hours On
// My original canPlace function (BROKEN):
function canPlace(slot, word, grid) {
for (let i = 0; i < slot.len; i++) {
// ... check logic ...
return true // โ ๐ inside the loop! Only checked first letter!
}
}
Yes. I really did that. Returned true after checking only the first character. My puzzle was accepting "abc" into a slot that needed "axc" because it saw the 'a' matched and dipped.
Shoutout to Phil Arturo ๐
Phil, you kept telling me: "You need to understand the fundamentals, not just the frameworks."
I laughed then. I cry-laughed while debugging that return true at 11pm.
You were right. Vanilla JS humbles you. But it also teaches you how to think in loops, indices, and grid coordinates without a linter holding your hand.
The Fixed Version (Works Now, I Swear)
function canPlace(slot, word, grid) {
const {row, col, len, dir} = slot;
if (word.length !== len) return false;
for (let i = 0; i < len; i++) {
let r = row, c = col;
if (dir === 'across') c = col + i;
else r = row + i;
const gridChar = grid[r][c];
const wordChar = word[i];
if (gridChar !== '.' && gridChar !== wordChar) {
return false; // Conflict!
}
}
return true; // โ OUTSIDE the loop, where it belongs
}
Final Takeaway
React is awesome. Vite is lightning fast. But once in a while, build something with just JavaScript, a terminal, and console.log debugging.
You'll feel stupid for 30 minutes. Then you'll feel like a god.
And you'll never put a return inside a loop again. ๐ค
Thanks again Phil Arturo โ this one's for you.
Top comments (0)