Skip to content

Add new brain game: Word Ladder#122

Open
lautyscanio wants to merge 5 commits into
ajaynegi33:mainfrom
lautyscanio:feature/word-ladder-game
Open

Add new brain game: Word Ladder#122
lautyscanio wants to merge 5 commits into
ajaynegi33:mainfrom
lautyscanio:feature/word-ladder-game

Conversation

@lautyscanio

@lautyscanio lautyscanio commented May 5, 2026

Copy link
Copy Markdown

User description

  • Landing page with Easy / Medium / Hard difficulty selector
  • Full gameplay: transform start word into target one letter at a time
  • BFS-powered hint system showing the next optimal word
  • Lives system: Easy=5, Medium=3, Hard=2 (lost on invalid words)
  • Step counter + progress bar per puzzle
  • Optimal path revealed on game over
  • Fully responsive from 320px to desktop
  • Word dictionaries for 3, 4 and 5-letter words
  • Cognitive benefits & scientific backing section documented
  • Registered in /game card grid

Closes #117


CodeAnt-AI Description

Add the Word Ladder brain game with difficulty selection and guided play

What Changed

  • Added Word Ladder to the games grid so players can open the new game from the main game selection page
  • Added a landing page with Easy, Medium, and Hard choices, plus clear rules, an example chain, and cognitive benefits content
  • Added the full game experience: transform a start word into the target word one letter at a time, track steps, lives, hints used, and remaining moves
  • Added hint support that shows the next best word, and a loss screen that reveals a possible optimal path
  • Added responsive layouts for both the landing page and gameplay screen across mobile and desktop

Impact

✅ Faster access to a new word puzzle
✅ Clearer guidance for first-time players
✅ Fewer failed runs from invalid word entries

🔄 Retrigger CodeAnt AI Review

Details

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

- Landing page with Easy / Medium / Hard difficulty selector
- Full gameplay: transform start word into target one letter at a time
- BFS-powered hint system showing the next optimal word
- Lives system: Easy=5, Medium=3, Hard=2 (lost on invalid words)
- Step counter + progress bar per puzzle
- Optimal path revealed on game over
- Fully responsive from 320px to desktop
- Word dictionaries for 3, 4 and 5-letter words
- Cognitive benefits & scientific backing section documented
- Registered in /game card grid

Closes ajaynegi33#117
@vercel

vercel Bot commented May 5, 2026

Copy link
Copy Markdown

@lautyscanio is attempting to deploy a commit to the ajaynegi45's projects Team on Vercel.

A member of the Team first needs to authorize it.

@codeant-ai

codeant-ai Bot commented May 5, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown

👋 Hello @lautyscanio!

Thanks for contributing to Old-School-Game – a curated collection of classic, brain-training games that boost memory, focus, creativity, and long-term brain health 🎯🧠.

In today's world full of short-form distractions, this project helps rebuild deep focus and mental endurance through thoughtful gameplay.


✅ Important Things To Do:

  • 🌟 Don’t forget to ⭐ Star the repo and follow @ajaynegi45 for updates, ideas, and dev insights.
  • 📬 Stay inspired! Sign up for the monthly CodiesCoder Newsletter – we explore one key software engineering topic each month, beginner-friendly and fun to read!

✅ Your pull request has been submitted successfully, and a maintainer will review it soon.

@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@lautyscanio has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 37 minutes and 55 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8c9b810e-c276-4fb8-b07c-198b2c4ea79b

📥 Commits

Reviewing files that changed from the base of the PR and between 32135ab and 7c9c16a.

📒 Files selected for processing (3)
  • src/app/game/word-ladder/play/WordLadderGame.tsx
  • src/app/game/word-ladder/play/page.module.css
  • src/app/game/word-ladder/wordList.ts

Walkthrough

A comprehensive Word Ladder game implementation is added to the application. The feature includes a landing page with difficulty selection, a playable game component with turn-based word submission and validation, word dictionaries for 3–5 letter words, puzzle definitions for three difficulty levels, BFS shortest-path computation for optimal solutions, and integration into the main game menu.

Changes

Word Ladder Game Feature

Layer / File(s) Summary
Data & Game Logic
src/app/game/word-ladder/wordList.ts
Exports word dictionaries (WORDS_3, WORDS_4, WORDS_5), difficulty-specific puzzle pairs (PUZZLES_EASY/MEDIUM/HARD), and core utilities: puzzle/word selection, validation (word membership, single-letter transitions), BFS shortest-path search, and hint generation.
Core Game Component
src/app/game/word-ladder/play/WordLadderGame.tsx
Implements game state (puzzle, chain, lives, steps, game status), word submission with validation, error handling with animations, hint system with BFS integration, and dual-outcome cards (win with stats / loss with optimal-path calculation via dynamic BFS import).
Landing Page
src/app/game/word-ladder/page.tsx
Renders difficulty selection UI with state management, hero section, rules, cognitive benefits, scientific backing list, and navigation to play route with selected difficulty as query parameter.
Play Page Wrapper
src/app/game/word-ladder/play/page.tsx
Wraps WordLadderGame in Suspense boundary with loading fallback.
Styling & Layout
src/app/game/word-ladder/page.module.css, src/app/game/word-ladder/play/page.module.css
Landing page CSS defines hero, difficulty grid, sections, and benefits layout; play page CSS provides HUD (stats, lives, progress), tile variants (target, changed, won), chain display, input controls, error shake animation, result cards, and optimal-path visualization; both include responsive breakpoints for 480px and 360px.
Menu Integration
src/app/game/page.tsx
Adds Word Ladder Card entry to game selection UI with imported WordLadderImage, custom colors (#F97316, white text), and route link to word-ladder.

Sequence Diagram

sequenceDiagram
    actor User
    participant Menu as Game Menu
    participant Landing as Landing Page
    participant Play as Play Component
    participant Logic as Game Logic
    participant Dict as Dictionary/BFS

    User->>Menu: Select Word Ladder
    Menu->>Landing: Navigate to /word-ladder
    Landing->>Landing: Render difficulty picker
    User->>Landing: Select difficulty & click Start
    Landing->>Play: Navigate with difficulty param
    Play->>Logic: Initialize puzzle from getRandomPuzzle()
    Logic->>Landing: Render game UI (target, chain, input)
    
    loop Gameplay
        User->>Play: Type word and submit
        Play->>Logic: Validate word (length, 1 diff, dictionary)
        Logic->>Dict: Check isValidWord()
        Dict-->>Logic: Word found/not found
        Logic->>Logic: Update chain, lives, steps
        Logic-->>Play: Render updated state or error
        User->>Play: See error or continue
    end
    
    alt Player wins
        Logic->>Play: Render win card with stats
        User->>Play: Click Play Again or Back
    else Player loses
        Logic->>Dict: Compute BFS path (optimal solution)
        Dict-->>Logic: Return shortest path
        Logic->>Play: Render loss card with optimal path
        User->>Play: Review solution then proceed
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The PR spans seven new files with heterogeneous logic: word-list management and BFS algorithms require careful verification of correctness; game state transitions and validation logic need thorough testing across edge cases (e.g., word length mismatches, repeating words, dictionary boundaries); UI/state management is spread across multiple components; and 954 lines of CSS, while mostly repetitive, still demand visual testing across responsive breakpoints.

Suggested Labels

enhancement, level3, size:XL

Poem

A ladder made of words, rung by rung,
From cold to warm, transformations spun.
One letter shifts through memory's maze,
Building neural pathways through the haze—
🧠✨ Cognition climbs toward brighter days. ✨🧠

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a new Word Ladder brain game to the project.
Description check ✅ Passed The description comprehensively explains the Word Ladder game features including landing page, difficulty levels, gameplay mechanics, hint system, lives system, responsive design, and integration into the game grid.
Linked Issues check ✅ Passed The PR successfully implements all core requirements from issue #117: word transformation gameplay, dictionary validation, step limits, difficulty levels, hint system via BFS, cognitive benefits documentation, and scientific backing references.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the Word Ladder game as specified in issue #117, with no extraneous modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label May 5, 2026
@lautyscanio lautyscanio mentioned this pull request May 5, 2026
2 tasks
@coderabbitai coderabbitai Bot added enhancement New feature or request level3 size:XL This PR changes 500-999 lines, ignoring generated files labels May 5, 2026
Comment thread src/app/game/word-ladder/play/WordLadderGame.tsx Outdated
Comment on lines +262 to +270
display: flex;
align-items: center;
gap: 10px;
padding: 6px 10px;
border-radius: 12px;
background: transparent;
transition: background 0.2s;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The chain row is forced into a single flex line with no wrapping, but in hard mode it contains index + 5 tiles + badge, which can exceed narrow mobile widths (~320px) and cause horizontal overflow/clipping. Allow wrapping or add a mobile rule that reflows/removes non-critical inline elements on very small screens. [logic error]

Severity Level: Major ⚠️
- ⚠️ Hard-mode chains overflow on narrow phones (~320px wide).
- ⚠️ Horizontal scrolling/clipping degrades readability of word tiles.
Steps of Reproduction ✅
1. From the landing page `src/app/game/word-ladder/page.tsx`, select Hard difficulty and
click the Start button (`handleStart` at lines 39-41) which navigates to
`/game/word-ladder/play?difficulty=hard` via `router.push`.

2. The route `/game/word-ladder/play` renders `WordLadderPlayPage`
(`src/app/game/word-ladder/play/page.tsx:1-11`), which in turn renders `<WordLadderGame
/>` inside a `Suspense` boundary, making `WordLadderGame.tsx` the main play UI.

3. `WordLadderGame` pulls a hard puzzle of 5-letter words via the helpers in
`src/app/game/word-ladder/wordList.ts` (`PUZZLES_HARD` at lines 7-25 and `getRandomPuzzle`
at 47-50), and renders the word chain in a list at `WordLadderGame.tsx:93-127` using `<div
className={styles.chainRow}>` for each word, containing: an index badge
(`styles.chainIndex`), a `<div className={styles.wordRow}>` that holds the tiles, and, for
the first row, a `<span className={styles.startBadge}>Start</span>`.

4. On a 320px-wide device, the play container from `play/page.module.css:6-13` has
`max-width: 680px` and horizontal padding `20px 16px`, yielding ~288px of inner width. The
word tiles use `.tile` (`:191-205`) with width 48px by default, reduced to 40px at `@media
(max-width: 480px)` (`:35-41`) and 34px at `@media (max-width: 360px)` (`:73-79`), while
`.wordRow` (`:185-189`) is a non-wrapping flex row. For hard mode (5-letter words), the
first chain row layout (index badge width 24px, padding-left/right 10px each, two 10px
gaps, five tiles at ≥34px, and a `startBadge` with padding and text) combined with
`.chainRow`'s flex container (`display: flex; gap: 10px; padding: 6px 10px;` at
`:262-270`) exceeds the available ~288px inner width. Because neither `.chainRow` nor
`.wordRow` enable wrapping (no `flex-wrap: wrap`), the row cannot break and instead
overflows horizontally, causing tile/start-badge clipping or horizontal scrolling on small
screens despite the 320px responsiveness requirement.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/app/game/word-ladder/play/page.module.css
**Line:** 262:270
**Comment:**
	*Logic Error: The chain row is forced into a single flex line with no wrapping, but in hard mode it contains index + 5 tiles + badge, which can exceed narrow mobile widths (~320px) and cause horizontal overflow/clipping. Allow wrapping or add a mobile rule that reflows/removes non-critical inline elements on very small screens.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 476d523

Added flex-wrap: wrap and min-width: 0 to .chainRow so tiles
reflow naturally on narrow screens instead of clipping.

Additionally, at ≤360px (the smallest devices):

  • .startBadge is hidden to free horizontal space
  • .chainIndex shrinks from 24px to 18px

Hard mode (5 tiles) now renders correctly down to 320px.

Comment on lines +63 to +72
const difficulty = (searchParams.get('difficulty') ?? 'medium') as Difficulty

const [puzzle, setPuzzle] = useState<PuzzlePair | null>(null)
const [chain, setChain] = useState<string[]>([])
const [input, setInput] = useState('')
const [status, setStatus] = useState<GameStatus>('playing')
const [error, setError] = useState<ErrorKind>(null)
const [hint, setHint] = useState<string | null>(null)
const [hintsUsed, setHintsUsed] = useState(0)
const [lives, setLives] = useState(MAX_LIVES[difficulty])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The difficulty query parameter is force-cast instead of validated, so an invalid URL value (for example ?difficulty=foo) makes MAX_LIVES[difficulty] become undefined. That breaks life tracking (lives - 1 becomes NaN) and can leave the game in an unwinnable state where life-loss logic no longer works. Validate the param against allowed values and fall back to a safe default before using it. [logic error]

Severity Level: Major ⚠️
- ❌ Invalid difficulty query breaks life tracking and display.
- ⚠️ Players see "No lives left" but keep playing.
- ⚠️ Lives-based game-over never triggers for malformed difficulty.
Steps of Reproduction ✅
1. From the game grid at `src/app/game/page.tsx:66-72`, click the "Word Ladder" card (link
`word-ladder`) to open the Word Ladder landing page at
`src/app/game/word-ladder/page.tsx`.

2. In the browser location bar, manually navigate to
`/game/word-ladder/play?difficulty=foo` instead of using the difficulty picker; this
renders `WordLadderPlayPage` (`src/app/game/word-ladder/play/page.tsx:6-10`), which mounts
`WordLadderGame` (`WordLadderGame.tsx:60`).

3. On first render, `WordLadderGame` reads the query parameter via `useSearchParams()` and
assigns `difficulty = 'foo'` at `WordLadderGame.tsx:62-64`, then initialises `lives` with
`useState(MAX_LIVES[difficulty])` at `WordLadderGame.tsx:72`. Because `MAX_LIVES` is only
defined for `'easy' | 'medium' | 'hard'` (`WordLadderGame.tsx:50-54`), `MAX_LIVES['foo']`
is `undefined`, so `lives` and `maxLives` (`WordLadderGame.tsx:76`) are both `undefined`.

4. Start playing and intentionally enter an invalid, non-dictionary word so
`isValidWord(word)` fails inside `handleSubmit` (`WordLadderGame.tsx:131-139`). The code
computes `const newLives = lives - 1` at `WordLadderGame.tsx:133`, which becomes `NaN - 1
=> NaN`, sets `lives` to `NaN` via `setLives(newLives)`, and checks `if (newLives <= 0)`
at `WordLadderGame.tsx:135`, which is always false for `NaN`. As a result, the lives-based
loss condition never triggers, while the UI shows zero hearts (`maxLives` is effectively
0) and the text "No lives left" (`WordLadderGame.tsx:231-233`), demonstrating broken life
tracking and a mismatch between UI and game-over logic when `difficulty` is an invalid URL
value.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/app/game/word-ladder/play/WordLadderGame.tsx
**Line:** 63:72
**Comment:**
	*Logic Error: The `difficulty` query parameter is force-cast instead of validated, so an invalid URL value (for example `?difficulty=foo`) makes `MAX_LIVES[difficulty]` become `undefined`. That breaks life tracking (`lives - 1` becomes `NaN`) and can leave the game in an unwinnable state where life-loss logic no longer works. Validate the param against allowed values and fall back to a safe default before using it.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c0bf619

Replaced the unsafe as Difficulty cast with a parseDifficulty()
validator that checks the query param against the explicit allowlist
['easy', 'medium', 'hard'], falling back to 'medium' on any
invalid or missing value.

This ensures MAX_LIVES[difficulty] and all derived state always
receive a valid Difficulty — never undefined, NaN or 0.

Comment on lines +164 to +169
const next = getHint(currentWord, puzzle.target)
if (next) {
setHint(next)
setHintsUsed((h: number) => h + 1)
} else {
setHint('no-path')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The hint system computes a path using only currentWord and target, but move validation later forbids reusing words already in the chain. Because used words are not excluded during hint generation, hints can recommend a move that is immediately rejected as already-used. Pass the used-word set into hint calculation (or filter hint output) so hints always propose legal moves. [logic error]

Severity Level: Major ⚠️
- ⚠️ Hint can suggest already-used words rejected as illegal.
- ⚠️ Players waste hints without actionable guidance or progress.
Steps of Reproduction ✅
1. From the Word Ladder landing page (`src/app/game/word-ladder/page.tsx:35-41`), select
the "Easy" difficulty and click "Start Game", which routes to
`/game/word-ladder/play?difficulty=easy` (`handleStart` at `page.tsx:39-41`) and mounts
`WordLadderGame` via `WordLadderPlayPage` (`src/app/game/word-ladder/play/page.tsx:6-10`).

2. When the randomly chosen easy puzzle is `{ start: 'CAT', target: 'DOG' }` defined in
`PUZZLES_EASY` (`src/app/game/word-ladder/wordList.ts:228-244`), submit the starting word
"CAT" (already in the chain), then type the valid intermediate word "CAR" and press
"Submit". `handleSubmit` in `WordLadderGame.tsx:105-154` accepts "CAR" because it is the
correct length, differs by exactly one letter (`diffCount` at
`WordLadderGame.tsx:121-123`), is not already in `chain` (`WordLadderGame.tsx:125-127`),
and is present in the 3-letter dictionary (`WORDS_3` at `wordList.ts:15-45` via
`isValidWord` at `wordList.ts:320-323`).

3. Click the "💡 Hint" button in the input area (`WordLadderGame.tsx:337-339`).
`handleHint` at `WordLadderGame.tsx:162-171` is called, and because `status ===
'playing'`, it invokes `getHint(currentWord, puzzle.target)` at `WordLadderGame.tsx:164`
with `currentWord === 'CAR'` and `puzzle.target === 'DOG'`. `getHint`
(`wordList.ts:395-403`) internally calls `bfs(current.toUpperCase(), target.toUpperCase(),
wordSet)` using the full 3-letter word set (`getWordSet(current.length)` at
`wordList.ts:399-400`), which computes a shortest path from `'CAR'` to `'DOG'` without
regard to which words are already present in the React `chain` state.

4. Because the global dictionary contains a shortest path `CAR → CAT → COT → COG → DOG`
that reuses the start word `'CAT'` (all words present in `WORDS_3` at
`wordList.ts:15-45`), `bfs` can return a shortest path whose second element is `'CAT'`, so
`getHint` returns `'CAT'` at `wordList.ts:401-402`. This value is stored in component
state via `setHint(next)` at `WordLadderGame.tsx:165` and shown to the player in the hint
box (`WordLadderGame.tsx:301-305). If the user follows that hint and submits "CAT",
`handleSubmit` hits the `chain.includes(word)` guard at `WordLadderGame.tsx:125-127` and
triggers the `'already-used'` error message, proving that hint generation can propose
moves that are immediately rejected as illegal because it ignores the `chain` of
previously used words.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/app/game/word-ladder/play/WordLadderGame.tsx
**Line:** 164:169
**Comment:**
	*Logic Error: The hint system computes a path using only `currentWord` and `target`, but move validation later forbids reusing words already in the chain. Because used words are not excluded during hint generation, hints can recommend a move that is immediately rejected as `already-used`. Pass the used-word set into hint calculation (or filter hint output) so hints always propose legal moves.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 476d523

getHint now accepts a usedWords: readonly string[] parameter.
The full player chain is passed in on every hint request:

const next = getHint(currentWord, puzzle.target, chain)

Internally, bfs() seeds its visited set with all already-used
words before starting the search, so the optimal path it returns
will never route through a word the player has already played.

If no valid path exists (all routes blocked by used words), the
hint shows "No path found from here — try a different route!" instead
of silently doing nothing.

@codeant-ai

codeant-ai Bot commented May 5, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

Prevents invalid URL values from causing MAX_LIVES[difficulty]
to return undefined, which would set lives=NaN and maxLives=0,
breaking the entire life system.

Now validates against the explicit allowlist ['easy','medium','hard']
and falls back to 'medium' on any unexpected value.
- fix(hint): pass used chain words to BFS so hints never suggest
  an already-used word (getHint now accepts usedWords param)
- fix(css): add flex-wrap + min-width:0 to .chainRow to prevent
  horizontal overflow on 320px screens in hard mode (5 tiles)
- fix(css): hide .startBadge and shrink .chainIndex at <=360px
  to free space for letter tiles on the smallest devices
- note: difficulty param validation was already fixed in c0bf619
@lautyscanio

Copy link
Copy Markdown
Author

Fixed in 476d523

  1. Hint ignores used wordsgetHint now accepts a usedWords param
    that seeds the BFS visited set, so it will never suggest a word
    already in the player's chain.

  2. Mobile chain overflow.chainRow now has flex-wrap: wrap and
    min-width: 0, allowing tiles to reflow on narrow screens instead of
    clipping.

  3. Very small screens (≤360px).startBadge is hidden and
    .chainIndex shrinks to free space for the letter tiles.

Note: the difficulty param validation was already addressed in c0bf619.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/game/word-ladder/play/page.module.css`:
- Around line 247-251: Rename the camelCase keyframe names popIn and fadeIn to
kebab-case (e.g., pop-in and fade-in) in the CSS `@keyframes` declarations and
update every animation/animation-name usage that references popIn or fadeIn (for
example any animation: or animation-name: properties) so they point to the new
kebab-case names; ensure you update both definitions and all usages (including
the other occurrence mentioned around lines 317-320) to satisfy the
keyframes-name-pattern Stylelint rule.

In `@src/app/game/word-ladder/play/WordLadderGame.tsx`:
- Line 63: The difficulty URL param is being cast unvalidated which lets invalid
values make MAX_LIVES[difficulty] undefined and break lives logic; update the
logic around searchParams.get('difficulty') and the difficulty constant (and any
initialization of lives that uses MAX_LIVES) to validate the string against the
allowed Difficulty values (e.g., check membership in the Difficulty union/enum
or keys of MAX_LIVES), falling back to 'medium' when invalid, so difficulty is
always a known key and MAX_LIVES[difficulty] yields a number; adjust the code
that reads searchParams, the const difficulty, and the lives initialiser to
perform this validation and fallback.

In `@src/app/game/word-ladder/wordList.ts`:
- Line 259: The puzzle entry { start: 'MINE', target: 'GOLD', maxSteps: 10 } in
wordList.ts allows 10 steps which conflicts with the landing page's
DIFFICULTY_INFO.medium.steps description (which says "Up to 9 steps"); fix by
either changing that entry's maxSteps to 9 or updating
DIFFICULTY_INFO.medium.steps in page.tsx to reflect "Up to 10 steps" so the data
and UI match, and ensure you update whichever symbol you choose: the object
literal in wordList.ts or the DIFFICULTY_INFO.medium.steps string in page.tsx.
- Around line 279-284: Update the PUZZLES_HARD array comments: fix the
duplicated word in the SHORE hint to end with "STARK" only, remove the stray
developer note "Hmm let me use a safer one" in the BLACK/SLACK comment, and
replace the invalid STAND→BRAND hint with a correct single-letter path hint such
as "STAND→BLAND→BRAND→BRAID→BRAIN" to match the { start: 'STAND', target:
'BRAIN', maxSteps: 8 } entry; locate these comments near the objects with start:
'SHORE' and start: 'STAND' and edit the inline comments accordingly.
- Around line 330-335: isValidStep currently uppercases the candidate word
(toUp) but then checks membership against getWordSet(...) which contains
lowercase words, causing valid steps to return false; fix by normalizing the
lookup to the same case (e.g., pass toUp.toLowerCase() to
getWordSet(...).has(...) or simply call the existing isValidWord(to) after the
diffCount check), keeping the length/diffCount logic
(diffCount(from.toUpperCase(), toUp) === 1) and using consistent casing for the
dictionary lookup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f9abfe36-eabf-4541-822e-7bba95ec1e91

📥 Commits

Reviewing files that changed from the base of the PR and between f8c6715 and 32135ab.

⛔ Files ignored due to path filters (1)
  • public/WordLadder.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • src/app/game/page.tsx
  • src/app/game/word-ladder/page.module.css
  • src/app/game/word-ladder/page.tsx
  • src/app/game/word-ladder/play/WordLadderGame.tsx
  • src/app/game/word-ladder/play/page.module.css
  • src/app/game/word-ladder/play/page.tsx
  • src/app/game/word-ladder/wordList.ts

Comment thread src/app/game/word-ladder/play/page.module.css Outdated
Comment thread src/app/game/word-ladder/play/WordLadderGame.tsx Outdated
Comment thread src/app/game/word-ladder/wordList.ts Outdated
Comment thread src/app/game/word-ladder/wordList.ts Outdated
Comment thread src/app/game/word-ladder/wordList.ts
- useCallback on handleSubmit, handleHint, handleKeyDown, triggerError
  to prevent unnecessary re-renders
- useMemo for usedWordSet (Set<string>) replacing O(n) chain.includes()
  with O(1) Set.has() on every submission
- Timeout cleanup: shakeTimerRef + lostTimerRef track pending timeouts,
  cleared on unmount and on initPuzzle to prevent stale state updates
- setLives uses functional updater (prev => next) to avoid stale
  closure over lives value
- parseDifficulty hardened: checks value !== null explicitly before
  the includes() call
- Constants (MAX_LIVES, ERROR_MESSAGES, VALID_DIFFICULTIES) moved to
  module scope so they are not recreated on every render
- initPuzzle cancels pending timers before resetting state
- fix(css): rename camelCase keyframe animations to kebab-case
  (popIn → pop-in, fadeIn → fade-in) to satisfy Stylelint
  keyframes-name-pattern rule; updated all animation: references

- fix(data): align MINE→GOLD maxSteps from 10 to 9 so it matches
  the 'Up to 9 steps' advertised on the Medium difficulty card

- fix(comments): clean up PUZZLES_HARD inline comments
  • SHORE path: remove duplicate STARK at the end
  • STAND path: remove stray dev note and fix invalid STAND→BRAND
    (changed 2 letters) to correct path STAND→BLAND→BRAND→BRAID→BRAIN

- fix(isValidStep): was always returning false for valid words
  because it checked uppercase against a lowercase dictionary;
  now delegates to isValidWord() for consistent case handling

- note: difficulty param validation was already fixed in c0bf619
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request level3 size:XL This PR changes 500-999 lines, ignoring generated files size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Word Ladder] <Word Ladder>

1 participant