ddd
This commit is contained in:
parent
0a343ecbc5
commit
c3a6f5ff37
80 changed files with 2512 additions and 1625 deletions
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
const {vm,assert,functionSource,loadAppLogic,app,css}=require('./helpers/app-source');
|
||||
const {createFrameScheduler}=require('../client/input/frame-scheduler');
|
||||
const AppLogic=loadAppLogic();
|
||||
const context={PAD:16,CELL:40,ckey:(r,c)=>`${r},${c}`};
|
||||
vm.createContext(context);
|
||||
|
|
@ -38,15 +39,16 @@ const centerVelocity=gestureContext.gesture.edgePanVelocity(500,400),rightVeloci
|
|||
assert(centerVelocity[0]===0&¢erVelocity[1]===0&&rightVelocity[0]>0,'Edge auto-pan velocity is not limited to the viewport edge');
|
||||
console.log('Direct snap threshold, outward gate reach, and edge auto-pan test passed');
|
||||
|
||||
const sampleContext={perfNow:()=>100,DRAG_MAX_POINTER_SAMPLES:12};
|
||||
let capturedPointerSample=null;
|
||||
const sampleContext={perfNow:()=>100,DRAG_MAX_POINTER_SAMPLES:12,ensureBoardDragScheduler:()=>({push:sample=>{capturedPointerSample=sample;return 1}})};
|
||||
vm.createContext(sampleContext);
|
||||
vm.runInContext(`${functionSource('pointerEventSamples')}\n${functionSource('trimBoardPointerSamples')}\n${functionSource('setBoardPointerSample')}\n${functionSource('appendBoardPointerSamples')}\nthis.pointer={pointerEventSamples,appendBoardPointerSamples};`,sampleContext);
|
||||
const cornerSamples=[
|
||||
{clientX:220,clientY:280},{clientX:140,clientY:280},{clientX:140,clientY:196},
|
||||
{clientX:290,clientY:196},{clientX:290,clientY:250}
|
||||
],sampleBoard={pendingPointerMove:null};
|
||||
],sampleBoard={};
|
||||
sampleContext.pointer.appendBoardPointerSamples(sampleBoard,{pointerId:12,pointerType:'pen',getCoalescedEvents:()=>cornerSamples});
|
||||
assert(JSON.stringify([sampleBoard.pendingPointerMove.clientX,sampleBoard.pendingPointerMove.clientY])===JSON.stringify([290,250])&&sampleBoard.pointerMoveSamples.length===1,'Pointer coalescing did not retain the newest sample in the bounded logic queue');
|
||||
assert(JSON.stringify([capturedPointerSample.clientX,capturedPointerSample.clientY])===JSON.stringify([290,250]),'Pointer coalescing did not retain the newest sample in the bounded logic queue');
|
||||
const threeTurnPath={startGate:0,endGate:null,cells:[[4,6],[4,5],[4,4],[4,3],[4,2],[4,1],[3,1],[2,1],[2,2],[2,3],[3,3]]};
|
||||
assert(AppLogic.analyzePathTurns(threeTurnPath,[[4,6,'E']],[],false).count===3,'The pictured left-up-right-down pickup gesture does not display three turns');
|
||||
assert(!functionSource('extendPointerTo').includes('consumeBufferedPointerTurn'),'Pickup drag still extends a speculative second cell');
|
||||
|
|
@ -83,7 +85,7 @@ const mergeContext={
|
|||
metaState:()=>mergeState,manhattan:(a,b)=>Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]),ckey:(r,c)=>`${r},${c}`,cellSet:p=>p.validSet,
|
||||
cancelBoardDragFrame:()=>cancelledMergeFrames++,
|
||||
applyBoardCommand:(_board,mutate)=>mutate()===false?false:true,
|
||||
safeRelease:()=>releasedMergePointers++,playSound:()=>{},queueMicrotask:callback=>callback(),reconcileDrawingPresentation:()=>{}
|
||||
safeRelease:()=>releasedMergePointers++,commitConnectedLineVisuals:()=>{},playSound:()=>{},queueMicrotask:callback=>callback(),reconcileDrawingPresentation:()=>{}
|
||||
};
|
||||
vm.createContext(mergeContext);
|
||||
vm.runInContext(`${functionSource('openTipMergePlan')}\n${functionSource('joinTips')}\nthis.joinTips=joinTips;`,mergeContext);
|
||||
|
|
@ -96,15 +98,20 @@ assert(!app.includes('function pickupJoinStepsAtPoint')&&!app.includes('function
|
|||
let cameraCallback=null,cameraTimerCallback=null,cameraApplies=0;
|
||||
const cameraContext={
|
||||
CAMERA_DISPLAY_WATCHDOG_MS:18,DRAG_FRAME_INTERVAL:1000/60,
|
||||
cam:{x:0,y:0,scale:1},cameraInteractionFrame:0,cameraInteractionDelayTimer:0,cameraInteractionLastDraw:0,pendingCameraInteraction:null,
|
||||
cam:{x:0,y:0,scale:1},pendingCameraInteraction:null,
|
||||
requestAnimationFrame:callback=>{cameraCallback=callback;return 7},cancelAnimationFrame:()=>{},setTimeout:callback=>{cameraTimerCallback=callback;return 8},clearTimeout:()=>{},applyCamera:immediate=>{assert(immediate===true,'Queued camera update was not committed directly')},
|
||||
perfNow:()=>100,perfStart:()=>0,perfEnd:()=>0,perfCount:()=>{},recordInteractionCommit:()=>{},observeInteractionFrame:()=>{},data:{cameraAnchor:null},currentCameraAnchor:()=>({centerX:0,centerY:0,scale:1}),markGlobalDirty:()=>{},
|
||||
};
|
||||
vm.createContext(cameraContext);
|
||||
vm.runInContext(`${functionSource('commitCameraInteraction')}\n${functionSource('queueCameraInteraction')}\nthis.queueCameraInteraction=queueCameraInteraction;`,cameraContext);
|
||||
vm.runInContext(`${functionSource('commitCameraInteraction')}\nthis.commitCameraInteraction=commitCameraInteraction;`,cameraContext);
|
||||
cameraContext.cameraInteractionScheduler=createFrameScheduler({
|
||||
requestFrame:cameraContext.requestAnimationFrame,cancelFrame:cameraContext.cancelAnimationFrame,setDelay:cameraContext.setTimeout,clearDelay:cameraContext.clearTimeout,
|
||||
now:cameraContext.perfNow,interval:1000/60,tolerance:1.25,watchdogDelay:18,commit:(next,timestamp)=>cameraContext.commitCameraInteraction(next,timestamp)
|
||||
});
|
||||
vm.runInContext(`${functionSource('queueCameraInteraction')}\nthis.queueCameraInteraction=queueCameraInteraction;`,cameraContext);
|
||||
cameraContext.applyCamera=()=>cameraApplies++;
|
||||
cameraContext.queueCameraInteraction({x:10,y:20,scale:1});cameraContext.queueCameraInteraction({x:30,y:40,scale:1});
|
||||
assert(cameraContext.cameraInteractionFrame===7&&cameraContext.cam.x===0,'Raw pan events were applied before the animation frame');
|
||||
assert(cameraContext.cameraInteractionScheduler.inspect().armed&&cameraContext.cam.x===0,'Raw pan events were applied before the animation frame');
|
||||
cameraCallback();
|
||||
assert(cameraContext.cam.x===30&&cameraContext.cam.y===40&&cameraApplies===1,'Pan events were not coalesced to the latest frame');
|
||||
cameraTimerCallback();
|
||||
|
|
@ -155,15 +162,17 @@ const shopItems=[{id:'O1'},{id:'O2'},...Array.from({length:12},(_,index)=>({id:`
|
|||
assert(functionSource('renderStorePanel').includes('storeInventoryItems(meta,store)')&&functionSource('renderStorePanel').includes("'store-cursor':'store-other'"),'Shop rendering bypasses the fixed 2+12 item inventory');
|
||||
const storeRateContext={
|
||||
STORE_CHANCE:.10,hash32:value=>value>>>0,LOCAL_SOLVER:'tester',STORE_PRICE_VERSION:1,SCORE_VERSION:3,
|
||||
trustedNow:()=>1000,currentPlayerName:()=>"tester",seededStoreItemIds:()=>shopItems.map(item=>item.id),storePriceDetails:()=>({coefficient:1})
|
||||
trustedNow:()=>1000,currentPlayerName:()=>"tester",seededStoreItemIds:()=>shopItems.map(item=>item.id),storePriceDetails:()=>({coefficient:1}),puzzleOf:meta=>meta.puzzle
|
||||
};
|
||||
vm.createContext(storeRateContext);
|
||||
vm.runInContext(`${functionSource('maybeOpenStore')}\nthis.maybeOpenStore=maybeOpenStore;`,storeRateContext);
|
||||
vm.runInContext(`${functionSource('storeObstacleCell')}\n${functionSource('maybeOpenStore')}\nthis.maybeOpenStore=maybeOpenStore;`,storeRateContext);
|
||||
const eligibleStoreState=()=>({solved:true,store:null,paths:[{cells:[[0,0],[0,1]]}]});
|
||||
const storeMeta={seed:1,puzzle:{obstacles:[[1,1],[2,2]]}};
|
||||
const belowThreshold=eligibleStoreState(),atThreshold=eligibleStoreState();
|
||||
storeRateContext.maybeOpenStore({seed:1},belowThreshold,0,.099999);
|
||||
storeRateContext.maybeOpenStore({seed:1},atThreshold,0,.10);
|
||||
storeRateContext.maybeOpenStore(storeMeta,belowThreshold,0,.099999);
|
||||
storeRateContext.maybeOpenStore(storeMeta,atThreshold,0,.10);
|
||||
assert(belowThreshold.store&&atThreshold.store===null,'Shop appearance boundary is not exactly 1/10');
|
||||
assert(storeMeta.puzzle.obstacles.some(cell=>cell[0]===belowThreshold.store.cell[0]&&cell[1]===belowThreshold.store.cell[1]),'Shop did not replace an obstacle cell');
|
||||
|
||||
assert(!app.includes('function overviewShopAtClient(')&&!functionSource('beginPan').includes('overviewShopAtClient'),'Zoomed-out view still has a shop-only hit target absent from the minimap');
|
||||
|
||||
|
|
@ -232,7 +241,8 @@ const reconnectContext={
|
|||
metaState:()=>reconnectState,usedGateSet:()=>new Set(),LINE_COLORS:['#0af','#fa0','#0f0'],canonicalGateColorIndex:()=>1,
|
||||
applyBoardCommand:(_board,mutate)=>{mutate();return true},neighborColor:()=>null,playSound:()=>{},
|
||||
usesLightweightDragOverlay:()=>false,requestAnimationFrame:callback=>callback(),
|
||||
gateConnectEffect:(_board,_gate,color)=>gateEffects.push(color),queueMicrotask:callback=>callback(),reconcileDrawingPresentation:()=>{}
|
||||
gateConnectEffect:(_board,_gate,color)=>gateEffects.push(color),queueMicrotask:callback=>callback(),reconcileDrawingPresentation:()=>{},
|
||||
commitConnectedLineVisuals:()=>{},cancelBoardDragFrame:()=>{},clearDragRender:()=>{},hidePickupHandleOverlay:()=>{},safeRelease:()=>{}
|
||||
};
|
||||
vm.createContext(reconnectContext);
|
||||
vm.runInContext(`${functionSource('finalizeAtGate')}\nthis.finalizeAtGate=finalizeAtGate;`,reconnectContext);
|
||||
|
|
@ -279,7 +289,7 @@ console.log('Connected-gate dragging and two-handle line disappearance tests pas
|
|||
assert(!app.includes('RETRACTION_HOLD_MS')&&!app.includes('pendingRetraction'),'Own-line retraction still has a delayed state');
|
||||
assert(functionSource('extendOne').includes('path.cells.splice(rewind+1)')&&functionSource('extendPointerTo').includes('rewindActivePathToCell(b,targetCell'),'Original immediate own-line shortening was not restored');
|
||||
assert(functionSource('gateFromPointOrCell').includes('maxPixels:0')&&!functionSource('extendPointerTo').includes('gateConnectionSteps'),'A knob can still snap to a gate from an adjacent cell');
|
||||
assert(functionSource('shouldTeleportToUnsolvedBoard').includes('return false')&&!functionSource('bindBoard').includes('centerMeta(')&&!app.includes('function promoteStaticBoard('),'Board input can still promote a summary or teleport the camera');
|
||||
assert(!app.includes('shouldTeleportToUnsolvedBoard')&&!functionSource('bindBoard').includes('centerMeta(')&&!app.includes('function promoteStaticBoard('),'Board input can still promote a summary or teleport the camera');
|
||||
assert(functionSource('matchingNumberKeys').includes('partialTurnCount')&&functionSource('updateNumberMatchFeedback').includes("classList.toggle('number-match',current.size>0)")&&functionSource('updateNumberMatchFeedback').includes("matchOrbit.classList.toggle('show'")&&css.includes('@keyframes numberMatchOrbit')&&css.includes('stroke-dasharray:1.2 5.35'),'Matching turn-number feedback does not keep an enlarged knob with a rotating perforated orbit');
|
||||
assert(functionSource('renderBoardNow').includes("'\\u66f2\\u304c\\u308b'")&&app.includes('numberLayer.append(node,warning)')&&css.includes('.number-turn-warning.show{opacity:1}'),'The 曲がる warning is not prominent or is behind the number');
|
||||
console.log('Immediate retraction, exact-cell gate, no-click-teleport, and number-match feedback guards passed');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue