DEV Community

Benjamin Koimett
Benjamin Koimett

Posted on

I built a crossword solver without React and survived to tell the tale ๐Ÿ˜…

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;
}
Enter fullscreen mode Exit fullscreen mode

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!
  }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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.


vanillajs #crossword #webdev #reactdev #fundamentals

Top comments (0)