Skip to content

Add hidden Rift Mode for unsolvable puzzle states - #23

Closed
ssfinney wants to merge 3 commits into
mainfrom
codex/design-and-build-rift-mode-feature
Closed

Add hidden Rift Mode for unsolvable puzzle states#23
ssfinney wants to merge 3 commits into
mainfrom
codex/design-and-build-rift-mode-feature

Conversation

@ssfinney

Copy link
Copy Markdown
Owner

Motivation

  • Introduce a subtle, polished hidden “Rift Mode” that activates only when a user move pushes the board from solvable to truly unsolvable, turning an otherwise frustrating state into a restrained, extendable meta-event.
  • Ensure the trigger is robust (not just a red cell) by combining immediate contradiction checks with a solver-backed feasibility check so the feature only fires on genuinely impossible boards.
  • Keep the experience tasteful, mobile-friendly, and reversible while making the architecture reusable for later story/secret-layer extensions.

Description

  • Add solver-backed validation utilities: hasImmediateContradiction(board) and hasAnySolution(board) and a guarded trigger flow evaluateRiftTrigger() that fires only on origin==='player-move'.
  • Add Rift state and snapshot support: riftState, lastSolvableSnapshot, captureLastSolvableSnapshot(), snapshotCurrentState(), restoreLastSolvableState(), and helper setInteractionLocked() to guard input during sequences.
  • Implement the Rift sequence and UI: triggerRiftEvent() (glitch + staged status lines + node discovery), tappable rift-node rendering in render(), and openRiftModal() with modal actions Return, Restore last solvable, and Start fresh.
  • Persist Rift and last-solvable snapshot in the save payload and restore them in applyLoadedData(), clear transient Rift UI on lifecycle reset points (newGame(), restoreSnapshot(), applyLoadedData()), add reduced-motion support, and mark rift nodes with a non-color diamond affordance.
  • Files changed: script.js (core logic, new functions, state, render changes), index.html (rift modal markup), style.css (rift visuals, animation, reduced-motion), and sw.js (cache name bumped to v5 so clients pick up static changes).

Testing

  • Automated linting: ran npm run lint (ESLint over script.js and sw.js) and it passed.
  • Save/load sanity: Rift state and lastSolvableSnapshot are encoded into the save payload and restored on resume via applyLoadedData() (covered by code-path updates and save format change).
  • Manual interaction note: interactive verification (touch/gesture + in-browser flows) should be exercised on device/browser to confirm timing, haptics, undo/redo, and PWA resume behavior; this CLI run only executed linting automatically.

Codex Task

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a novel 'Rift Mode' feature to enhance the player experience when a Sudoku puzzle becomes unsolvable due to a player's move. Instead of simply hitting a dead end, players are presented with a unique, interactive event that offers options to recover or restart, adding a layer of depth and intrigue to otherwise frustrating situations. The implementation includes robust logic to accurately detect unsolvable states, a new user interface for interaction, and ensures seamless persistence across game sessions.

Highlights

  • Rift Mode Introduction: Implemented a hidden 'Rift Mode' that activates when a player's move renders the puzzle truly unsolvable, transforming a frustrating state into an extendable meta-event.
  • Robust Trigger Mechanism: The Rift Mode trigger is robust, combining immediate contradiction checks with a solver-backed feasibility check to ensure it only fires on genuinely impossible board states.
  • State Management and Persistence: Added comprehensive state management for Rift Mode, including capturing the last solvable snapshot, managing the Rift's active state, and persisting these states in the game's save payload.
  • Interactive UI and User Experience: Introduced a new Rift modal with options to return, restore the last solvable state, or start fresh, alongside visual glitch effects, staged status lines, and distinct 'rift node' markings on the board, with support for reduced motion.
  • Solver-Backed Validation: Integrated new utility functions, hasImmediateContradiction and hasAnySolution, to programmatically determine the solvability of the current board state.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a new 'Rift Mode' feature to the Shandoku game, adding a modal UI, new game state variables, and logic to detect unsolvable board states and trigger special events. Key changes include new functions for checking board solvability (hasImmediateContradiction, hasAnySolution), managing game state snapshots, handling user interaction locking, and displaying dynamic status messages. The new mode integrates with existing game mechanics like undo/redo, new game creation, and persistence. Review comments highlight opportunities to improve performance by removing redundant hasAnySolution calls in undo and redo functions, and to enhance maintainability by refactoring duplicated contradiction-checking logic and consolidating riftState initialization into a shared constant.

Comment thread script.js
future.push({grid:cloneGrid(grid),notes:cloneNotes(notes),selected:selected?{...selected}:null,elapsed,notesMode,autoCleanup});
restoreSnapshot(history.pop());
setStatus('Undid last move.');
boardWasSolvable=hasAnySolution(grid);

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.

high

This line is redundant and introduces a significant performance issue. The restoreSnapshot() function called on line 230 already triggers a call to hasAnySolution() via captureLastSolvableSnapshot(), which correctly sets the boardWasSolvable flag. This extra call means the expensive solver function is run twice on every undo operation. The same issue exists in the redo() function. Removing this line will fix the performance issue without affecting logic.

Comment thread script.js
history.push({grid:cloneGrid(grid),notes:cloneNotes(notes),selected:selected?{...selected}:null,elapsed,notesMode,autoCleanup});
restoreSnapshot(future.pop());
setStatus('Redid move.');
boardWasSolvable=hasAnySolution(grid);

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.

high

This line is redundant and introduces a significant performance issue. The restoreSnapshot() function called on line 238 already triggers a call to hasAnySolution() via captureLastSolvableSnapshot(), which correctly sets the boardWasSolvable flag. This extra call means the expensive solver function is run twice on every redo operation. The same issue exists in the undo() function. Removing this line will fix the performance issue without affecting logic.

Comment thread script.js
Comment on lines +115 to +148
function hasImmediateContradiction(board){
for(let r=0;r<GRID_SIZE;r++){
const seen=new Set();
for(let c=0;c<GRID_SIZE;c++){
const v=board[r][c];
if(!v) continue;
if(seen.has(v)) return true;
seen.add(v);
}
}
for(let c=0;c<GRID_SIZE;c++){
const seen=new Set();
for(let r=0;r<GRID_SIZE;r++){
const v=board[r][c];
if(!v) continue;
if(seen.has(v)) return true;
seen.add(v);
}
}
for(let br=0;br<GRID_SIZE;br+=3){
for(let bc=0;bc<GRID_SIZE;bc+=3){
const seen=new Set();
for(let r=br;r<br+3;r++){
for(let c=bc;c<bc+3;c++){
const v=board[r][c];
if(!v) continue;
if(seen.has(v)) return true;
seen.add(v);
}
}
}
}
return false;
}

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.

medium

The logic to check for contradictions in rows, columns, and boxes is duplicated three times. To improve maintainability and reduce code repetition, you could extract the duplicate-checking logic into a helper function that operates on an array of values. While this might involve creating temporary arrays for columns and boxes, the improvement in code clarity and ease of future modifications would be substantial, and the performance impact should be negligible for this operation.

Comment thread script.js Outdated
Comment thread script.js Outdated
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

🌸 Diff Haiku

In puzzle’s deep rift,
Unsolvable paths now bloom—
A secret unfolds.


Generated by spit-the-diff

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@ssfinney ssfinney closed this Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant