feat: add v2 queued taps and free board rotation
This commit is contained in:
+5
-5
@@ -28,9 +28,8 @@ test('mutual blocking reaches a fixed point; move shortage is separate',()=>{
|
||||
const easy=level([{q:0,r:0},{q:0,r:-1}],[tile('a',0,0),tile('b',0,-1)],1);
|
||||
assert.equal(solve(easy).stuck.length,0);assert.equal(solve(easy).solvable,false);
|
||||
});
|
||||
test('all 24 campaign levels validate, solve and increase in score',()=>{
|
||||
let previous=-1;
|
||||
for(const l of LEVELS){assert.deepEqual(validateLevel(l),[]);const a=analyze(l);assert.ok(a.solvable,l.name);assert.ok(a.rotations>=1);assert.equal(solve(l).solvable,false);assert.ok(a.score>=previous);previous=a.score;const g=new Game(l);for(const action of a.actions){if(action.type==='rotate')assert.equal(g.rotate(action.direction).status,'rotated');else assert.equal(g.tap(action.id).status,'exit');}assert.ok(g.won);assert.ok(g.moves>=0);}
|
||||
test('all 24 campaign levels retain their order, validate and solve with free rotations',()=>{
|
||||
for(const l of LEVELS){assert.deepEqual(validateLevel(l),[]);const a=analyze(l);assert.ok(a.solvable,l.name);assert.ok(a.rotations>=1);assert.equal(solve(l).solvable,false);assert.ok(a.score>=0&&a.score<=100);const g=new Game(l);for(const action of a.actions){if(action.type==='rotate')assert.equal(g.rotate(action.direction).status,'rotated');else assert.equal(g.tap(action.id).status,'exit');}assert.ok(g.won);assert.ok(g.moves>=0);}
|
||||
});
|
||||
test('100 generated seeds are deterministic and solvable',()=>{
|
||||
for(let seed=0;seed<100;seed++){const l=generateLevel(seed,seed%2?2:3,seed%2?15:32,.8);assert.deepEqual(validateLevel(l),[]);assert.ok(solve(l).solvable,`seed ${seed}`);assert.ok(l.tiles.length>0);}
|
||||
@@ -62,7 +61,7 @@ test('six board rotations restore tracks; tokens and arrows stay fixed',()=>{
|
||||
let board=l;for(let i=0;i<6;i++)board=rotateBoard(board);
|
||||
assert.deepEqual(board,l);
|
||||
const g=new Game(l),original=clone(g.tiles),before=clone(g.level.cells);
|
||||
assert.equal(g.rotate(1).status,'rotated');assert.deepEqual(g.tiles,original);assert.notDeepEqual(g.level.cells,before);assert.equal(g.orientation,1);assert.equal(g.moves,l.moveLimit-1);
|
||||
assert.equal(g.rotate(1).status,'rotated');assert.deepEqual(g.tiles,original);assert.notDeepEqual(g.level.cells,before);assert.equal(g.orientation,1);assert.equal(g.moves,l.moveLimit);
|
||||
assert.ok(g.undo());assert.equal(g.orientation,0);assert.deepEqual(g.level.cells,before);assert.equal(g.moves,l.moveLimit);
|
||||
});
|
||||
test('a stuck orientation can be rescued by rotating and must not immediately lose',()=>{
|
||||
@@ -83,8 +82,9 @@ test('swept segment detection cannot tunnel through a collider between frames',(
|
||||
const hit=segmentHexHit({x:-10,y:0},{x:10,y:0},{x:0,y:0});assert.ok(hit>0&&hit<1);
|
||||
assert.equal(segmentHexHit({x:-10,y:3},{x:10,y:3},{x:0,y:0}),null);
|
||||
});
|
||||
test('rotation step cost is included in the minimum move budget',()=>{
|
||||
test('free rotations are excluded from the minimum move budget',()=>{
|
||||
const l=clone(LEVELS[0]),a=solveRotations(l);assert.ok(a.rotations>0);
|
||||
assert.equal(a.minimumMoves,l.tiles.length);l.moveLimit=l.tiles.length;assert.ok(solveRotations(l).solvable);const g=new Game(l);for(const action of a.actions){if(action.type==='rotate'){const before=g.moves;g.rotate(action.direction);assert.equal(g.moves,before);}else g.tap(action.id);}assert.ok(g.won);assert.equal(g.moves,0);
|
||||
l.moveLimit=a.minimumMoves-1;const tooShort=solveRotations(l);assert.equal(tooShort.reachable,true);assert.equal(tooShort.solvable,false);
|
||||
});
|
||||
test('irregular boards retain classic play and do not rotate tiles off the base',()=>{
|
||||
|
||||
Reference in New Issue
Block a user