Skip to content

Commit cab67e3

Browse files
committed
Throttle Rift solvability checks with conflict-aware gating
1 parent 15ce83e commit cab67e3

1 file changed

Lines changed: 20 additions & 6 deletions

File tree

script.js

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
const RIFT_STATUS_DELAY_MS = 950;
99
const RIFT_STATUS_DELAY_REDUCED_MOTION_MS = 500;
1010
const RIFT_EVALUATE_DEBOUNCE_MS = 140;
11+
const RIFT_NON_CONFLICT_CHECK_INTERVAL = 5;
1112

1213
const boardEl = document.getElementById('board');
1314
const statusEl = document.getElementById('status');
@@ -45,6 +46,7 @@
4546
let statusSequenceId = 0;
4647
let interactionLocked = false;
4748
let riftEvalTimer = null;
49+
let movesSinceSolvabilityCheck = 0;
4850
let riftState = {
4951
active:false,
5052
sequenceRunning:false,
@@ -296,6 +298,7 @@
296298
riftState.active=false;
297299
riftState.sequenceRunning=false;
298300
riftState.nodes=[];
301+
movesSinceSolvabilityCheck=0;
299302
boardShellEl.classList.remove('rift-active','rift-glitch');
300303
statusEl.classList.remove('rift-status');
301304
riftModal.hidden=true;
@@ -362,10 +365,19 @@
362365
saveGame();
363366
}
364367

365-
function evaluateRiftTrigger(origin='system'){
368+
function evaluateRiftTrigger(origin='system', options={}){
366369
if(origin!=='player-move') return;
367370
if(riftState.active||riftState.sequenceRunning) return;
368371
if(Date.now()<riftState.cooldownUntil) return;
372+
if(!options.force){
373+
if(options.conflictIntroduced){
374+
movesSinceSolvabilityCheck=0;
375+
} else {
376+
movesSinceSolvabilityCheck++;
377+
if(movesSinceSolvabilityCheck<RIFT_NON_CONFLICT_CHECK_INTERVAL) return;
378+
movesSinceSolvabilityCheck=0;
379+
}
380+
}
369381
const solvable=hasAnySolution(grid);
370382
if(solvable){
371383
boardWasSolvable=true;
@@ -378,11 +390,11 @@
378390
}
379391
}
380392

381-
function scheduleRiftEvaluation(origin='player-move'){
393+
function scheduleRiftEvaluation(origin='player-move', options={}){
382394
if(riftEvalTimer) clearTimeout(riftEvalTimer);
383395
riftEvalTimer=setTimeout(()=>{
384396
riftEvalTimer=null;
385-
evaluateRiftTrigger(origin);
397+
evaluateRiftTrigger(origin, options);
386398
},RIFT_EVALUATE_DEBOUNCE_MS);
387399
}
388400

@@ -663,6 +675,7 @@
663675
boardShellEl.classList.remove('victory-glow');
664676
clearRiftVisualState();
665677
riftState={active:false,sequenceRunning:false,nodes:[],hasTriggered:false,cooldownUntil:0,copyKey:'pattern'};
678+
movesSinceSolvabilityCheck=0;
666679
captureLastSolvableSnapshot();
667680
render(); startTimer(); saveGame(); hideSplash();
668681
setStatus(`New ${difficultyEl.value} Shandoku game loaded.`);
@@ -683,16 +696,17 @@
683696
grid[r][c]=n;
684697
notes[r][c].clear();
685698
autoCleanNotesAround(r,c,n);
699+
const introducedConflict=hasConflict(r,c);
686700
render(); saveGame();
687-
if(hasConflict(r,c)){
701+
if(introducedConflict){
688702
vibrate([10,50,10]);
689703
const cellEl=boardEl.querySelector(`[data-r="${r}"][data-c="${c}"]`);
690704
if(cellEl){ cellEl.classList.add('error-shake'); setTimeout(()=>cellEl.classList.remove('error-shake'),400); }
691705
} else {
692706
vibrate(10);
693707
}
694708
if(isSolved()){ setStatus('Solved. Nice work.'); celebrate(); }
695-
scheduleRiftEvaluation('player-move');
709+
scheduleRiftEvaluation('player-move',{conflictIntroduced:introducedConflict});
696710
}
697711

698712
function clearSelected(){
@@ -704,7 +718,7 @@
704718
grid[r][c]=0; notes[r][c].clear();
705719
render(); saveGame();
706720
setStatus('Cell cleared.');
707-
scheduleRiftEvaluation('player-move');
721+
scheduleRiftEvaluation('player-move',{conflictIntroduced:false});
708722
}
709723

710724
function jumpToNextEmpty(){

0 commit comments

Comments
 (0)