mirror of
https://github.com/tiennm99/pikachu.git
synced 2026-05-29 16:25:03 +00:00
fix: Z-pattern logic, eliminate code duplication, fix tests
- Fix Z-pattern to use proper 2-turn path (H-V-H and V-H-V scanning) instead of single midpoint which only duplicated L-pattern behavior - Eliminate ~390 lines of duplicated pattern-matching code from PikachuGame.js by delegating to PikachuGameLogic via shared board ref - Fix removeCards to reset type=0 so pattern matching works after removal - Fix Jest config: remove invalid preset, add ESM support for Windows - Rename log.js to log.cjs for CommonJS compatibility with ESM project - Fix test expectations to account for pattern priority and border routing
This commit is contained in:
@@ -1,12 +1,4 @@
|
||||
export default {
|
||||
// Use ES modules
|
||||
preset: 'node',
|
||||
extensionsToTreatAsEsm: ['.js'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
useESM: true
|
||||
}
|
||||
},
|
||||
transform: {},
|
||||
|
||||
// Test environment
|
||||
|
||||
+11
-11
@@ -22,19 +22,19 @@
|
||||
"javascript"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "node log.js dev & next dev -p 8080",
|
||||
"build": "node log.js build & next build",
|
||||
"dev": "node log.cjs dev & next dev -p 8080",
|
||||
"build": "node log.cjs build & next build",
|
||||
"dev-nolog": "next dev -p 8080",
|
||||
"build-nolog": "next build",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:i": "jest test/patterns/i-pattern.test.js",
|
||||
"test:l": "jest test/patterns/l-pattern.test.js",
|
||||
"test:u": "jest test/patterns/u-pattern.test.js",
|
||||
"test:z": "jest test/patterns/z-pattern.test.js",
|
||||
"test:verbose": "jest --verbose",
|
||||
"test:silent": "jest --silent"
|
||||
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
|
||||
"test:watch": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --watch",
|
||||
"test:coverage": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --coverage",
|
||||
"test:i": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js test/patterns/i-pattern.test.js",
|
||||
"test:l": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js test/patterns/l-pattern.test.js",
|
||||
"test:u": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js test/patterns/u-pattern.test.js",
|
||||
"test:z": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js test/patterns/z-pattern.test.js",
|
||||
"test:verbose": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --verbose",
|
||||
"test:silent": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --silent"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "15.3.1",
|
||||
|
||||
@@ -295,14 +295,26 @@ export class PikachuGameLogic {
|
||||
}
|
||||
|
||||
checkZPattern(start, end) {
|
||||
// H-V-H: horizontal, vertical, horizontal (scan connecting columns)
|
||||
for (let col = 0; col < this.matrixWidth; col++) {
|
||||
if (col === start.col || col === end.col) continue;
|
||||
if (this.board[start.row][col].type !== 0) continue;
|
||||
if (this.board[end.row][col].type !== 0) continue;
|
||||
if (this.isPathClear(start, {row: start.row, col}) &&
|
||||
this.isPathClear({row: start.row, col}, {row: end.row, col}) &&
|
||||
this.isPathClear({row: end.row, col}, end)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// V-H-V: vertical, horizontal, vertical (scan connecting rows)
|
||||
for (let row = 0; row < this.matrixHeight; row++) {
|
||||
for (let col = 0; col < this.matrixWidth; col++) {
|
||||
if (this.board[row][col].type !== 0) continue;
|
||||
|
||||
const midPoint = {row, col};
|
||||
if (this.isPathClear(start, midPoint) && this.isPathClear(midPoint, end)) {
|
||||
return true;
|
||||
}
|
||||
if (row === start.row || row === end.row) continue;
|
||||
if (this.board[row][start.col].type !== 0) continue;
|
||||
if (this.board[row][end.col].type !== 0) continue;
|
||||
if (this.isPathClear(start, {row, col: start.col}) &&
|
||||
this.isPathClear({row, col: start.col}, {row, col: end.col}) &&
|
||||
this.isPathClear({row, col: end.col}, end)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -465,14 +477,30 @@ export class PikachuGameLogic {
|
||||
}
|
||||
|
||||
checkZPatternWithPath(start, end) {
|
||||
// H-V-H: scan connecting columns
|
||||
for (let col = 0; col < this.matrixWidth; col++) {
|
||||
if (col === start.col || col === end.col) continue;
|
||||
if (this.board[start.row][col].type !== 0) continue;
|
||||
if (this.board[end.row][col].type !== 0) continue;
|
||||
const corner1 = {row: start.row, col};
|
||||
const corner2 = {row: end.row, col};
|
||||
if (this.isPathClear(start, corner1) &&
|
||||
this.isPathClear(corner1, corner2) &&
|
||||
this.isPathClear(corner2, end)) {
|
||||
return [start, corner1, corner2, end];
|
||||
}
|
||||
}
|
||||
// V-H-V: scan connecting rows
|
||||
for (let row = 0; row < this.matrixHeight; row++) {
|
||||
for (let col = 0; col < this.matrixWidth; col++) {
|
||||
if (this.board[row][col].type !== 0) continue;
|
||||
|
||||
const midPoint = {row, col};
|
||||
if (this.isPathClear(start, midPoint) && this.isPathClear(midPoint, end)) {
|
||||
return [start, midPoint, end];
|
||||
}
|
||||
if (row === start.row || row === end.row) continue;
|
||||
if (this.board[row][start.col].type !== 0) continue;
|
||||
if (this.board[row][end.col].type !== 0) continue;
|
||||
const corner1 = {row, col: start.col};
|
||||
const corner2 = {row, col: end.col};
|
||||
if (this.isPathClear(start, corner1) &&
|
||||
this.isPathClear(corner1, corner2) &&
|
||||
this.isPathClear(corner2, end)) {
|
||||
return [start, corner1, corner2, end];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { EventBus } from '../EventBus';
|
||||
import { Scene } from 'phaser';
|
||||
import { PikachuGameLogic } from '../logic/PikachuGameLogic';
|
||||
|
||||
export class PikachuGame extends Scene
|
||||
{
|
||||
@@ -18,6 +19,7 @@ export class PikachuGame extends Scene
|
||||
this.gameStarted = false;
|
||||
this.debugLines = [];
|
||||
this.debugMode = false;
|
||||
this.logic = new PikachuGameLogic(this.boardWidth, this.boardHeight);
|
||||
}
|
||||
|
||||
create ()
|
||||
@@ -157,6 +159,7 @@ export class PikachuGame extends Scene
|
||||
}
|
||||
}
|
||||
|
||||
this.logic.board = this.board;
|
||||
this.renderBoard();
|
||||
this.gameStarted = true;
|
||||
}
|
||||
@@ -221,7 +224,7 @@ export class PikachuGame extends Scene
|
||||
// Check if cards are of the same type
|
||||
if (firstCell.type === secondCell.type) {
|
||||
// Check if there's a valid path between them
|
||||
const pathResult = this.hasValidPathWithDebug(first, second);
|
||||
const pathResult = this.logic.hasValidPathWithDebug(first, second);
|
||||
if (pathResult.valid) {
|
||||
// Valid match - show green line and remove cards
|
||||
if (this.debugMode) {
|
||||
@@ -251,243 +254,6 @@ export class PikachuGame extends Scene
|
||||
}
|
||||
}
|
||||
|
||||
hasValidPath(start, end)
|
||||
{
|
||||
// Check I-pattern (straight line)
|
||||
if (this.checkIPattern(start, end)) return true;
|
||||
|
||||
// Check L-pattern (one turn)
|
||||
if (this.checkLPattern(start, end)) return true;
|
||||
|
||||
// Check U-pattern (two turns with border)
|
||||
if (this.checkUPattern(start, end)) return true;
|
||||
|
||||
// Check Z-pattern (two turns)
|
||||
if (this.checkZPattern(start, end)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
hasValidPathWithDebug(start, end)
|
||||
{
|
||||
// Check I-pattern (straight line)
|
||||
const iPath = this.checkIPatternWithPath(start, end);
|
||||
if (iPath) return { valid: true, path: iPath };
|
||||
|
||||
// Check L-pattern (one turn)
|
||||
const lPath = this.checkLPatternWithPath(start, end);
|
||||
if (lPath) return { valid: true, path: lPath };
|
||||
|
||||
// Check U-pattern (two turns with border)
|
||||
const uPath = this.checkUPatternWithPath(start, end);
|
||||
if (uPath) return { valid: true, path: uPath };
|
||||
|
||||
// Check Z-pattern (two turns)
|
||||
const zPath = this.checkZPatternWithPath(start, end);
|
||||
if (zPath) return { valid: true, path: zPath };
|
||||
|
||||
return { valid: false, path: null };
|
||||
}
|
||||
|
||||
checkIPattern(start, end)
|
||||
{
|
||||
// Horizontal line
|
||||
if (start.row === end.row) {
|
||||
const minCol = Math.min(start.col, end.col);
|
||||
const maxCol = Math.max(start.col, end.col);
|
||||
for (let col = minCol + 1; col < maxCol; col++) {
|
||||
if (this.board[start.row][col].visible) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Vertical line
|
||||
if (start.col === end.col) {
|
||||
const minRow = Math.min(start.row, end.row);
|
||||
const maxRow = Math.max(start.row, end.row);
|
||||
for (let row = minRow + 1; row < maxRow; row++) {
|
||||
if (this.board[row][start.col].visible) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
checkLineX(y1, y2, x)
|
||||
{
|
||||
// Find point have column max and min
|
||||
const min = Math.min(y1, y2);
|
||||
const max = Math.max(y1, y2);
|
||||
|
||||
// Run column
|
||||
for (let y = min + 1; y < max; y++) {
|
||||
if (this.board[x][y].type !== 0) { // if see barrier then die
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Not die -> success
|
||||
return true;
|
||||
}
|
||||
|
||||
checkLineY(x1, x2, y)
|
||||
{
|
||||
const min = Math.min(x1, x2);
|
||||
const max = Math.max(x1, x2);
|
||||
|
||||
for (let x = min + 1; x < max; x++) {
|
||||
if (this.board[x][y].type !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
checkLPattern(start, end)
|
||||
{
|
||||
// Try corner at start.row, end.col
|
||||
if (this.isPathClear(start, {row: start.row, col: end.col}) &&
|
||||
this.isPathClear({row: start.row, col: end.col}, end) &&
|
||||
this.board[start.row][end.col].type === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try corner at end.row, start.col
|
||||
if (this.isPathClear(start, {row: end.row, col: start.col}) &&
|
||||
this.isPathClear({row: end.row, col: start.col}, end) &&
|
||||
this.board[end.row][start.col].type === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
checkUPattern(start, end)
|
||||
{
|
||||
// Check more right
|
||||
if (this.checkMoreLineX(start, end, 1)) return true;
|
||||
// Check more left
|
||||
if (this.checkMoreLineX(start, end, -1)) return true;
|
||||
// Check more down
|
||||
if (this.checkMoreLineY(start, end, 1)) return true;
|
||||
// Check more up
|
||||
if (this.checkMoreLineY(start, end, -1)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
checkMoreLineX(start, end, type)
|
||||
{
|
||||
// Find point have y min
|
||||
const pMinY = start.col < end.col ? start : end;
|
||||
const pMaxY = start.col < end.col ? end : start;
|
||||
|
||||
// Find line and y begin
|
||||
let y = pMaxY.col + type;
|
||||
let row = pMinY.row;
|
||||
let colFinish = pMaxY.col;
|
||||
|
||||
if (type === -1) {
|
||||
colFinish = pMinY.col;
|
||||
y = pMinY.col + type;
|
||||
row = pMaxY.row;
|
||||
}
|
||||
|
||||
// Check if we can connect horizontally first
|
||||
if ((this.board[row][colFinish].type === 0 || pMinY.col === pMaxY.col) &&
|
||||
this.checkLineX(pMinY.col, pMaxY.col, row)) {
|
||||
|
||||
// Check extension beyond border
|
||||
while (y >= 0 && y < this.matrixWidth &&
|
||||
this.board[pMinY.row][y].type === 0 &&
|
||||
this.board[pMaxY.row][y].type === 0) {
|
||||
|
||||
if (this.checkLineY(pMinY.row, pMaxY.row, y)) {
|
||||
return true;
|
||||
}
|
||||
y += type;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
checkMoreLineY(start, end, type)
|
||||
{
|
||||
// Find point have x min
|
||||
const pMinX = start.row < end.row ? start : end;
|
||||
const pMaxX = start.row < end.row ? end : start;
|
||||
|
||||
let x = pMaxX.row + type;
|
||||
let col = pMinX.col;
|
||||
let rowFinish = pMaxX.row;
|
||||
|
||||
if (type === -1) {
|
||||
rowFinish = pMinX.row;
|
||||
x = pMinX.row + type;
|
||||
col = pMaxX.col;
|
||||
}
|
||||
|
||||
// Check if we can connect vertically first
|
||||
if ((this.board[rowFinish][col].type === 0 || pMinX.row === pMaxX.row) &&
|
||||
this.checkLineY(pMinX.row, pMaxX.row, col)) {
|
||||
|
||||
// Check extension beyond border
|
||||
while (x >= 0 && x < this.matrixHeight &&
|
||||
this.board[x][pMinX.col].type === 0 &&
|
||||
this.board[x][pMaxX.col].type === 0) {
|
||||
|
||||
if (this.checkLineX(pMinX.col, pMaxX.col, x)) {
|
||||
return true;
|
||||
}
|
||||
x += type;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
checkZPattern(start, end)
|
||||
{
|
||||
// Check all possible two-turn paths within the matrix
|
||||
for (let row = 0; row < this.matrixHeight; row++) {
|
||||
for (let col = 0; col < this.matrixWidth; col++) {
|
||||
if (this.board[row][col].type !== 0) continue;
|
||||
|
||||
const midPoint = {row, col};
|
||||
if (this.isPathClear(start, midPoint) && this.isPathClear(midPoint, end)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isPathClear(start, end)
|
||||
{
|
||||
if (start.row === end.row && start.col === end.col) return true;
|
||||
|
||||
// Horizontal path
|
||||
if (start.row === end.row) {
|
||||
const minCol = Math.min(start.col, end.col);
|
||||
const maxCol = Math.max(start.col, end.col);
|
||||
for (let col = minCol + 1; col < maxCol; col++) {
|
||||
if (this.board[start.row][col].type !== 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Vertical path
|
||||
if (start.col === end.col) {
|
||||
const minRow = Math.min(start.row, end.row);
|
||||
const maxRow = Math.max(start.row, end.row);
|
||||
for (let row = minRow + 1; row < maxRow; row++) {
|
||||
if (this.board[row][start.col].type !== 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
removeCards(first, second)
|
||||
{
|
||||
const firstCell = this.board[first.row][first.col];
|
||||
@@ -504,6 +270,8 @@ export class PikachuGame extends Scene
|
||||
secondCell.sprite.destroy();
|
||||
firstCell.visible = false;
|
||||
secondCell.visible = false;
|
||||
firstCell.type = 0;
|
||||
secondCell.type = 0;
|
||||
firstCell.sprite = null;
|
||||
secondCell.sprite = null;
|
||||
}
|
||||
@@ -638,7 +406,7 @@ export class PikachuGame extends Scene
|
||||
if (row1 === row2 && col1 === col2) continue;
|
||||
|
||||
if (this.board[row1][col1].type === this.board[row2][col2].type &&
|
||||
this.hasValidPath({row: row1, col: col1}, {row: row2, col: col2})) {
|
||||
this.logic.hasValidPath({row: row1, col: col1}, {row: row2, col: col2})) {
|
||||
|
||||
// Highlight the hint pair
|
||||
this.board[row1][col1].sprite.setTint(0xffff00);
|
||||
@@ -660,164 +428,6 @@ export class PikachuGame extends Scene
|
||||
}
|
||||
}
|
||||
|
||||
checkIPatternWithPath(start, end)
|
||||
{
|
||||
// Horizontal line
|
||||
if (start.row === end.row) {
|
||||
const minCol = Math.min(start.col, end.col);
|
||||
const maxCol = Math.max(start.col, end.col);
|
||||
for (let col = minCol + 1; col < maxCol; col++) {
|
||||
if (this.board[start.row][col].type !== 0) return null;
|
||||
}
|
||||
return [start, end];
|
||||
}
|
||||
|
||||
// Vertical line
|
||||
if (start.col === end.col) {
|
||||
const minRow = Math.min(start.row, end.row);
|
||||
const maxRow = Math.max(start.row, end.row);
|
||||
for (let row = minRow + 1; row < maxRow; row++) {
|
||||
if (this.board[row][start.col].type !== 0) return null;
|
||||
}
|
||||
return [start, end];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
checkLPatternWithPath(start, end)
|
||||
{
|
||||
// Try corner at start.row, end.col
|
||||
const corner1 = {row: start.row, col: end.col};
|
||||
if (this.isPathClear(start, corner1) &&
|
||||
this.isPathClear(corner1, end) &&
|
||||
this.board[start.row][end.col].type === 0) {
|
||||
return [start, corner1, end];
|
||||
}
|
||||
|
||||
// Try corner at end.row, start.col
|
||||
const corner2 = {row: end.row, col: start.col};
|
||||
if (this.isPathClear(start, corner2) &&
|
||||
this.isPathClear(corner2, end) &&
|
||||
this.board[end.row][start.col].type === 0) {
|
||||
return [start, corner2, end];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
checkUPatternWithPath(start, end)
|
||||
{
|
||||
// Check more right
|
||||
let path = this.checkMoreLineXWithPath(start, end, 1);
|
||||
if (path) return path;
|
||||
|
||||
// Check more left
|
||||
path = this.checkMoreLineXWithPath(start, end, -1);
|
||||
if (path) return path;
|
||||
|
||||
// Check more down
|
||||
path = this.checkMoreLineYWithPath(start, end, 1);
|
||||
if (path) return path;
|
||||
|
||||
// Check more up
|
||||
path = this.checkMoreLineYWithPath(start, end, -1);
|
||||
if (path) return path;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
checkMoreLineXWithPath(start, end, type)
|
||||
{
|
||||
// Find point have y min
|
||||
const pMinY = start.col < end.col ? start : end;
|
||||
const pMaxY = start.col < end.col ? end : start;
|
||||
|
||||
// Find line and y begin
|
||||
let y = pMaxY.col + type;
|
||||
let row = pMinY.row;
|
||||
let colFinish = pMaxY.col;
|
||||
|
||||
if (type === -1) {
|
||||
colFinish = pMinY.col;
|
||||
y = pMinY.col + type;
|
||||
row = pMaxY.row;
|
||||
}
|
||||
|
||||
// Check if we can connect horizontally first
|
||||
if ((this.board[row][colFinish].type === 0 || pMinY.col === pMaxY.col) &&
|
||||
this.checkLineX(pMinY.col, pMaxY.col, row)) {
|
||||
|
||||
// Check extension beyond border
|
||||
while (y >= 0 && y < this.matrixWidth &&
|
||||
this.board[pMinY.row][y].type === 0 &&
|
||||
this.board[pMaxY.row][y].type === 0) {
|
||||
|
||||
if (this.checkLineY(pMinY.row, pMaxY.row, y)) {
|
||||
// Create path with the connecting point
|
||||
const connectPoint1 = {row: pMinY.row, col: y};
|
||||
const connectPoint2 = {row: pMaxY.row, col: y};
|
||||
return [pMinY, connectPoint1, connectPoint2, pMaxY];
|
||||
}
|
||||
y += type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
checkMoreLineYWithPath(start, end, type)
|
||||
{
|
||||
// Find point have x min
|
||||
const pMinX = start.row < end.row ? start : end;
|
||||
const pMaxX = start.row < end.row ? end : start;
|
||||
|
||||
let x = pMaxX.row + type;
|
||||
let col = pMinX.col;
|
||||
let rowFinish = pMaxX.row;
|
||||
|
||||
if (type === -1) {
|
||||
rowFinish = pMinX.row;
|
||||
x = pMinX.row + type;
|
||||
col = pMaxX.col;
|
||||
}
|
||||
|
||||
// Check if we can connect vertically first
|
||||
if ((this.board[rowFinish][col].type === 0 || pMinX.row === pMaxX.row) &&
|
||||
this.checkLineY(pMinX.row, pMaxX.row, col)) {
|
||||
|
||||
// Check extension beyond border
|
||||
while (x >= 0 && x < this.matrixHeight &&
|
||||
this.board[x][pMinX.col].type === 0 &&
|
||||
this.board[x][pMaxX.col].type === 0) {
|
||||
|
||||
if (this.checkLineX(pMinX.col, pMaxX.col, x)) {
|
||||
// Create path with the connecting point
|
||||
const connectPoint1 = {row: x, col: pMinX.col};
|
||||
const connectPoint2 = {row: x, col: pMaxX.col};
|
||||
return [pMinX, connectPoint1, connectPoint2, pMaxX];
|
||||
}
|
||||
x += type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
checkZPatternWithPath(start, end)
|
||||
{
|
||||
// Check all possible two-turn paths within the matrix
|
||||
for (let row = 0; row < this.matrixHeight; row++) {
|
||||
for (let col = 0; col < this.matrixWidth; col++) {
|
||||
if (this.board[row][col].type !== 0) continue;
|
||||
|
||||
const midPoint = {row, col};
|
||||
if (this.isPathClear(start, midPoint) && this.isPathClear(midPoint, end)) {
|
||||
return [start, midPoint, end];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
shuffleArray(array)
|
||||
{
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
|
||||
+61
-80
@@ -2,18 +2,17 @@ import { PikachuBaseTest } from './base/PikachuBaseTest.js';
|
||||
|
||||
describe('All Patterns Integration Tests', () => {
|
||||
let tester;
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
tester = new PikachuBaseTest();
|
||||
});
|
||||
|
||||
describe('Pattern Priority', () => {
|
||||
test('should prefer I-pattern over all other patterns', () => {
|
||||
// Simple horizontal line should use I-pattern
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 5, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'I-pattern priority',
|
||||
matrix,
|
||||
@@ -21,16 +20,15 @@ describe('All Patterns Integration Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should prefer L-pattern over U and Z patterns', () => {
|
||||
// Simple L-shape should use L-pattern
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-pattern priority',
|
||||
matrix,
|
||||
@@ -38,26 +36,25 @@ describe('All Patterns Integration Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should use U-pattern when I and L patterns are blocked', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 1, 3, 2);
|
||||
tester.placeCard(matrix, 3, 1, 2);
|
||||
|
||||
tester.placeCard(matrix, 4, 5, 1);
|
||||
tester.placeCard(matrix, 4, 9, 1);
|
||||
// Block I-pattern
|
||||
tester.placeCard(matrix, 4, 7, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern when simpler patterns blocked',
|
||||
'U-pattern when I-pattern blocked',
|
||||
matrix,
|
||||
1, 1, 3, 3,
|
||||
4, 5, 4, 9,
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -65,23 +62,10 @@ describe('All Patterns Integration Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 4, 4, 1);
|
||||
// Block L-pattern
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 2, 4, 2);
|
||||
tester.placeCard(matrix, 4, 2, 2);
|
||||
// Block U-pattern by filling border extensions
|
||||
for (let i = 1; i <= 20; i++) {
|
||||
if (i !== 2 && i !== 4) {
|
||||
tester.placeCard(matrix, 2, i, 2);
|
||||
tester.placeCard(matrix, 4, i, 2);
|
||||
}
|
||||
}
|
||||
for (let i = 1; i <= 8; i++) {
|
||||
if (i !== 2 && i !== 4) {
|
||||
tester.placeCard(matrix, i, 2, 2);
|
||||
tester.placeCard(matrix, i, 4, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern as last resort',
|
||||
matrix,
|
||||
@@ -89,7 +73,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -99,7 +83,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 5, 2); // different type
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Different card types should fail',
|
||||
matrix,
|
||||
@@ -108,7 +92,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
null,
|
||||
'Cards are different types'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -116,7 +100,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
// No card at (1, 5)
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Empty positions should fail',
|
||||
matrix,
|
||||
@@ -125,14 +109,14 @@ describe('All Patterns Integration Tests', () => {
|
||||
null,
|
||||
'One or both positions are empty'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should handle same position selection', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Same position should fail',
|
||||
matrix,
|
||||
@@ -141,17 +125,17 @@ describe('All Patterns Integration Tests', () => {
|
||||
null,
|
||||
'Cannot select the same position'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should handle out of bounds positions', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
|
||||
|
||||
tester.game.loadBoardFromMatrix(matrix);
|
||||
const result = tester.game.testMove(1, 1, 0, 0); // Out of bounds
|
||||
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.error).toContain('out of bounds');
|
||||
});
|
||||
@@ -162,7 +146,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 3, 1);
|
||||
|
||||
|
||||
// Both I-pattern and L-pattern are possible, should choose I-pattern
|
||||
const testCase = tester.createTestCase(
|
||||
'Multiple valid patterns - choose simplest',
|
||||
@@ -171,35 +155,32 @@ describe('All Patterns Integration Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should handle dense board with limited connection options', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 8, 20, 1);
|
||||
|
||||
// Fill most positions but leave some paths open
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 1, 3, 2);
|
||||
tester.placeCard(matrix, 3, 1, 2);
|
||||
// Fill most other positions
|
||||
for (let row = 4; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
if (!((row === 1 && col === 1) || (row === 8 && col === 20))) {
|
||||
// Leave some strategic positions empty for connection
|
||||
if (!(row === 1 && col === 20) && !(row === 8 && col === 1) &&
|
||||
!(row === 4 && col === 10)) {
|
||||
tester.placeCard(matrix, row, col, 2);
|
||||
}
|
||||
}
|
||||
tester.placeCard(matrix, row, col, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Z-pattern should still work through col 2
|
||||
const testCase = tester.createTestCase(
|
||||
'Dense board with limited options',
|
||||
matrix,
|
||||
1, 1, 8, 20,
|
||||
true // Should find some pattern
|
||||
1, 1, 3, 3,
|
||||
true
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -207,7 +188,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 8, 20, 1);
|
||||
|
||||
|
||||
// Block all possible connection paths
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
@@ -216,14 +197,14 @@ describe('All Patterns Integration Tests', () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Impossible connections should fail',
|
||||
matrix,
|
||||
1, 1, 8, 20,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -235,17 +216,17 @@ describe('All Patterns Integration Tests', () => {
|
||||
tester.placeCard(matrix, 1, 20, 1); // top-right
|
||||
tester.placeCard(matrix, 8, 1, 1); // bottom-left
|
||||
tester.placeCard(matrix, 8, 20, 1); // bottom-right
|
||||
|
||||
|
||||
// Test all corner-to-corner connections
|
||||
const testCases = [
|
||||
[1, 1, 1, 20], // top-left to top-right
|
||||
[1, 1, 8, 1], // top-left to bottom-left
|
||||
[1, 1, 8, 20], // top-left to bottom-right
|
||||
[1, 20, 8, 20], // top-right to bottom-right
|
||||
[8, 1, 8, 20], // bottom-left to bottom-right
|
||||
[1, 20, 8, 1] // top-right to bottom-left
|
||||
[1, 1, 1, 20], // top-left to top-right (I-pattern)
|
||||
[1, 1, 8, 1], // top-left to bottom-left (I-pattern)
|
||||
[1, 1, 8, 20], // top-left to bottom-right (L-pattern)
|
||||
[1, 20, 8, 20], // top-right to bottom-right (I-pattern)
|
||||
[8, 1, 8, 20], // bottom-left to bottom-right (I-pattern)
|
||||
[1, 20, 8, 1] // top-right to bottom-left (Z-pattern, L corners occupied)
|
||||
];
|
||||
|
||||
|
||||
testCases.forEach(([r1, c1, r2, c2]) => {
|
||||
const testCase = tester.createTestCase(
|
||||
`Corner connection (${r1},${c1}) to (${r2},${c2})`,
|
||||
@@ -253,7 +234,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
r1, c1, r2, c2,
|
||||
true
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -263,7 +244,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
// Place cards along top edge
|
||||
tester.placeCard(matrix, 1, 5, 1);
|
||||
tester.placeCard(matrix, 1, 15, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Cards along board edge',
|
||||
matrix,
|
||||
@@ -271,7 +252,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -281,8 +262,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 4, 4, 1);
|
||||
|
||||
// This could potentially work with L, U, or Z patterns
|
||||
|
||||
// Should prefer L-pattern as it's simpler
|
||||
const testCase = tester.createTestCase(
|
||||
'Multiple pattern possibilities',
|
||||
@@ -291,7 +271,7 @@ describe('All Patterns Integration Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -299,20 +279,21 @@ describe('All Patterns Integration Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 6, 6, 1);
|
||||
|
||||
|
||||
// Block L-pattern
|
||||
tester.placeCard(matrix, 2, 6, 2);
|
||||
tester.placeCard(matrix, 6, 2, 2);
|
||||
|
||||
// Should fall back to U-pattern or Z-pattern
|
||||
|
||||
// Should fall back to Z-pattern
|
||||
const testCase = tester.createTestCase(
|
||||
'Cascading pattern fallbacks',
|
||||
matrix,
|
||||
2, 2, 6, 6,
|
||||
true
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { PikachuBaseTest } from '../base/PikachuBaseTest.js';
|
||||
|
||||
describe('I-Pattern Tests', () => {
|
||||
let tester;
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
tester = new PikachuBaseTest();
|
||||
});
|
||||
@@ -12,7 +12,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 5, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Horizontal line - clear path',
|
||||
matrix,
|
||||
@@ -20,23 +20,30 @@ describe('I-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should not connect cards with blocked horizontal path', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 3, 2); // blocking card
|
||||
tester.placeCard(matrix, 1, 5, 1);
|
||||
|
||||
// Fill entire board so no alternative patterns can route around
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
tester.placeCard(matrix, row, col, 2);
|
||||
}
|
||||
}
|
||||
// Place target cards in the middle (away from border)
|
||||
tester.placeCard(matrix, 4, 5, 1);
|
||||
tester.placeCard(matrix, 4, 7, 1);
|
||||
// (4,6) remains as blocker type 2
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Horizontal line - blocked path',
|
||||
matrix,
|
||||
1, 1, 1, 5,
|
||||
4, 5, 4, 7,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -44,7 +51,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 2, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Adjacent cards - horizontal',
|
||||
matrix,
|
||||
@@ -52,7 +59,7 @@ describe('I-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -60,7 +67,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 20, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Long horizontal line',
|
||||
matrix,
|
||||
@@ -68,7 +75,7 @@ describe('I-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -78,7 +85,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 4, 1, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Vertical line - clear path',
|
||||
matrix,
|
||||
@@ -86,23 +93,30 @@ describe('I-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should not connect cards with blocked vertical path', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 2, 1, 2); // blocking card
|
||||
tester.placeCard(matrix, 4, 1, 1);
|
||||
|
||||
// Fill entire board so no alternative patterns can route around
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
tester.placeCard(matrix, row, col, 2);
|
||||
}
|
||||
}
|
||||
// Place target cards in the middle
|
||||
tester.placeCard(matrix, 3, 10, 1);
|
||||
tester.placeCard(matrix, 5, 10, 1);
|
||||
// (4,10) remains as blocker type 2
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Vertical line - blocked path',
|
||||
matrix,
|
||||
1, 1, 4, 1,
|
||||
3, 10, 5, 10,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -110,7 +124,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 2, 1, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Adjacent cards - vertical',
|
||||
matrix,
|
||||
@@ -118,7 +132,7 @@ describe('I-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -126,7 +140,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 8, 1, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Long vertical line',
|
||||
matrix,
|
||||
@@ -134,31 +148,37 @@ describe('I-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
test('should not connect diagonal cards', () => {
|
||||
test('should not connect diagonal cards when all paths blocked', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
|
||||
// Fill entire board to block all patterns
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
tester.placeCard(matrix, row, col, 2);
|
||||
}
|
||||
}
|
||||
tester.placeCard(matrix, 4, 10, 1);
|
||||
tester.placeCard(matrix, 5, 11, 1);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Diagonal - should not work',
|
||||
'Diagonal - should not work when all paths blocked',
|
||||
matrix,
|
||||
1, 1, 2, 2,
|
||||
4, 10, 5, 11,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should not connect same position', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Same position - should fail',
|
||||
matrix,
|
||||
@@ -167,7 +187,7 @@ describe('I-Pattern Tests', () => {
|
||||
null,
|
||||
'Cannot select the same position'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -175,7 +195,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 5, 2); // different card type
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Different card types',
|
||||
matrix,
|
||||
@@ -184,7 +204,7 @@ describe('I-Pattern Tests', () => {
|
||||
null,
|
||||
'Cards are different types'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -192,7 +212,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
// Don't place card at (1,5)
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Empty position',
|
||||
matrix,
|
||||
@@ -201,7 +221,7 @@ describe('I-Pattern Tests', () => {
|
||||
null,
|
||||
'One or both positions are empty'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -211,7 +231,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1); // top-left corner
|
||||
tester.placeCard(matrix, 1, 20, 1); // top-right corner
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Cards at board edges',
|
||||
matrix,
|
||||
@@ -219,7 +239,7 @@ describe('I-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -227,7 +247,7 @@ describe('I-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1); // top-left
|
||||
tester.placeCard(matrix, 8, 1, 1); // bottom-left
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Cards at opposite corners',
|
||||
matrix,
|
||||
@@ -235,8 +255,8 @@ describe('I-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { PikachuBaseTest } from '../base/PikachuBaseTest.js';
|
||||
|
||||
describe('L-Pattern Tests', () => {
|
||||
let tester;
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
tester = new PikachuBaseTest();
|
||||
});
|
||||
@@ -12,7 +12,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape via first corner',
|
||||
matrix,
|
||||
@@ -20,7 +20,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 3, 1);
|
||||
tester.placeCard(matrix, 3, 1, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape via second corner',
|
||||
matrix,
|
||||
@@ -36,7 +36,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('L-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 3, 2); // block first corner
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape with one corner blocked',
|
||||
matrix,
|
||||
@@ -53,43 +53,54 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should fail when both corners are blocked', () => {
|
||||
test('should fail when both corners are blocked and no other path exists', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 3, 2); // block first corner
|
||||
tester.placeCard(matrix, 3, 1, 2); // block second corner
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
// Fill entire board to block all patterns
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
tester.placeCard(matrix, row, col, 2);
|
||||
}
|
||||
}
|
||||
// Place target cards in the middle
|
||||
tester.placeCard(matrix, 4, 8, 1);
|
||||
tester.placeCard(matrix, 6, 10, 1);
|
||||
// L-corners (4,10) and (6,8) remain blocked by fill
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape with both corners blocked',
|
||||
matrix,
|
||||
1, 1, 3, 3,
|
||||
4, 8, 6, 10,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Path Blocking', () => {
|
||||
test('should fail when path to corner is blocked', () => {
|
||||
test('should fail when all paths are completely blocked', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 2, 2); // block horizontal path
|
||||
tester.placeCard(matrix, 2, 1, 2); // block vertical path
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
// Fill entire board to prevent any pattern
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
tester.placeCard(matrix, row, col, 2);
|
||||
}
|
||||
}
|
||||
// Place target cards in the middle
|
||||
tester.placeCard(matrix, 4, 8, 1);
|
||||
tester.placeCard(matrix, 6, 10, 1);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape with blocked paths to corners',
|
||||
'L-shape with all paths blocked',
|
||||
matrix,
|
||||
1, 1, 3, 3,
|
||||
4, 8, 6, 10,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -98,7 +109,7 @@ describe('L-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 2, 2); // block horizontal path to first corner
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape with one path blocked',
|
||||
matrix,
|
||||
@@ -106,7 +117,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -116,7 +127,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 4, 1, 1);
|
||||
tester.placeCard(matrix, 1, 4, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Up-then-right turn',
|
||||
matrix,
|
||||
@@ -124,7 +135,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -132,7 +143,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 4, 1);
|
||||
tester.placeCard(matrix, 4, 1, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Down-then-left turn',
|
||||
matrix,
|
||||
@@ -140,7 +151,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -148,7 +159,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 3, 5, 1);
|
||||
tester.placeCard(matrix, 1, 2, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Left-then-up turn',
|
||||
matrix,
|
||||
@@ -156,7 +167,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -164,7 +175,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 2, 1);
|
||||
tester.placeCard(matrix, 3, 5, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Right-then-down turn',
|
||||
matrix,
|
||||
@@ -172,7 +183,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -182,7 +193,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1); // top-left corner
|
||||
tester.placeCard(matrix, 8, 20, 1); // bottom-right corner
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape at board edges',
|
||||
matrix,
|
||||
@@ -190,7 +201,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -198,7 +209,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1); // top-left
|
||||
tester.placeCard(matrix, 1, 20, 1); // top-right
|
||||
|
||||
|
||||
// This should be I-pattern, not L-pattern
|
||||
const testCase = tester.createTestCase(
|
||||
'Straight line at board boundary',
|
||||
@@ -207,7 +218,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -219,7 +230,7 @@ describe('L-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 2, 2, 2); // blocking card
|
||||
tester.placeCard(matrix, 3, 3, 2); // blocking card
|
||||
tester.placeCard(matrix, 5, 5, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape with multiple blocking cards',
|
||||
matrix,
|
||||
@@ -227,7 +238,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -235,12 +246,12 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 4, 4, 1);
|
||||
|
||||
|
||||
// Fill some positions but leave L-path open
|
||||
tester.placeCard(matrix, 3, 3, 2);
|
||||
tester.placeCard(matrix, 1, 1, 2);
|
||||
tester.placeCard(matrix, 5, 5, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'L-shape in dense board',
|
||||
matrix,
|
||||
@@ -248,7 +259,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -258,7 +269,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 2, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Adjacent cards should use I-pattern',
|
||||
matrix,
|
||||
@@ -266,7 +277,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -274,7 +285,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 10, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Straight line should use I-pattern',
|
||||
matrix,
|
||||
@@ -282,7 +293,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -292,7 +303,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Corner at middle position',
|
||||
matrix,
|
||||
@@ -300,7 +311,7 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -308,7 +319,7 @@ describe('L-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 6, 10, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Asymmetric L-shape',
|
||||
matrix,
|
||||
@@ -316,8 +327,8 @@ describe('L-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { PikachuBaseTest } from '../base/PikachuBaseTest.js';
|
||||
|
||||
describe('U-Pattern Tests', () => {
|
||||
let tester;
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
tester = new PikachuBaseTest();
|
||||
});
|
||||
@@ -14,7 +14,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 3, 5, 1);
|
||||
// Block direct vertical path
|
||||
tester.placeCard(matrix, 2, 5, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern extending right',
|
||||
matrix,
|
||||
@@ -22,7 +22,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 3, 15, 1);
|
||||
// Block direct vertical path
|
||||
tester.placeCard(matrix, 2, 15, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern extending left',
|
||||
matrix,
|
||||
@@ -40,7 +40,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -50,7 +50,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 1, 3, 1);
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 1, 2, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern extending down',
|
||||
matrix,
|
||||
@@ -58,7 +58,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -68,7 +68,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 8, 3, 1);
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 8, 2, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern extending up',
|
||||
matrix,
|
||||
@@ -76,7 +76,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -88,7 +88,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 1, 3, 1);
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 1, 2, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern at top-left corner',
|
||||
matrix,
|
||||
@@ -96,23 +96,25 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should handle U-pattern at opposite board corners', () => {
|
||||
test('should handle U-pattern at opposite board corners (same col)', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 8, 20, 1);
|
||||
|
||||
tester.placeCard(matrix, 8, 1, 1);
|
||||
// Block direct vertical path
|
||||
tester.placeCard(matrix, 4, 1, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern at opposite corners',
|
||||
'U-pattern at opposite corners same column',
|
||||
matrix,
|
||||
1, 1, 8, 20,
|
||||
1, 1, 8, 1,
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -120,7 +122,9 @@ describe('U-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 20, 1);
|
||||
tester.placeCard(matrix, 8, 20, 1);
|
||||
|
||||
// Block direct vertical path
|
||||
tester.placeCard(matrix, 4, 20, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern along right edge',
|
||||
matrix,
|
||||
@@ -128,7 +132,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -142,7 +146,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 3, 5, 2);
|
||||
tester.placeCard(matrix, 4, 5, 2);
|
||||
tester.placeCard(matrix, 5, 5, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern with multiple blocking cards',
|
||||
matrix,
|
||||
@@ -150,7 +154,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -158,7 +162,7 @@ describe('U-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 4, 4, 1);
|
||||
|
||||
|
||||
// Block all possible extension paths
|
||||
for (let i = 1; i <= 20; i++) {
|
||||
if (i !== 2 && i !== 4) {
|
||||
@@ -172,14 +176,14 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, i, 4, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern impossible - all paths blocked',
|
||||
matrix,
|
||||
2, 2, 4, 4,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -191,7 +195,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 4, 2, 1);
|
||||
// Block direct vertical path
|
||||
tester.placeCard(matrix, 3, 2, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Horizontal extension to right',
|
||||
matrix,
|
||||
@@ -199,7 +203,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -209,7 +213,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 4, 18, 1);
|
||||
// Block direct vertical path
|
||||
tester.placeCard(matrix, 3, 18, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Horizontal extension to left',
|
||||
matrix,
|
||||
@@ -217,7 +221,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -227,7 +231,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 6, 4, 1);
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 6, 3, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Vertical extension upward',
|
||||
matrix,
|
||||
@@ -235,7 +239,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -245,7 +249,7 @@ describe('U-Pattern Tests', () => {
|
||||
tester.placeCard(matrix, 2, 4, 1);
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 2, 3, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Vertical extension downward',
|
||||
matrix,
|
||||
@@ -253,7 +257,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -261,17 +265,19 @@ describe('U-Pattern Tests', () => {
|
||||
describe('Long Distance Connections', () => {
|
||||
test('should handle long distance U-pattern', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 8, 20, 1);
|
||||
|
||||
tester.placeCard(matrix, 4, 1, 1);
|
||||
tester.placeCard(matrix, 4, 20, 1);
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 4, 10, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Long distance U-pattern',
|
||||
matrix,
|
||||
1, 1, 8, 20,
|
||||
4, 1, 4, 20,
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -279,7 +285,9 @@ describe('U-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 4, 1, 1);
|
||||
tester.placeCard(matrix, 4, 20, 1);
|
||||
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 4, 5, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern across full board width',
|
||||
matrix,
|
||||
@@ -287,7 +295,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -295,7 +303,9 @@ describe('U-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 10, 1);
|
||||
tester.placeCard(matrix, 8, 10, 1);
|
||||
|
||||
// Block direct vertical path
|
||||
tester.placeCard(matrix, 4, 10, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'U-pattern across full board height',
|
||||
matrix,
|
||||
@@ -303,7 +313,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -313,7 +323,7 @@ describe('U-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 5, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Should prefer I-pattern',
|
||||
matrix,
|
||||
@@ -321,7 +331,7 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -329,7 +339,7 @@ describe('U-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Should prefer L-pattern',
|
||||
matrix,
|
||||
@@ -337,27 +347,26 @@ describe('U-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should use U-pattern when simpler patterns are blocked', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 4, 4, 1);
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 2, 4, 2);
|
||||
tester.placeCard(matrix, 4, 2, 2);
|
||||
|
||||
tester.placeCard(matrix, 4, 5, 1);
|
||||
tester.placeCard(matrix, 4, 9, 1);
|
||||
// Block I-pattern
|
||||
tester.placeCard(matrix, 4, 7, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Should use U-pattern when L-pattern blocked',
|
||||
'Should use U-pattern when I-pattern blocked',
|
||||
matrix,
|
||||
2, 2, 4, 4,
|
||||
4, 5, 4, 9,
|
||||
true,
|
||||
'U-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,77 +2,77 @@ import { PikachuBaseTest } from '../base/PikachuBaseTest.js';
|
||||
|
||||
describe('Z-Pattern Tests', () => {
|
||||
let tester;
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
tester = new PikachuBaseTest();
|
||||
});
|
||||
|
||||
describe('Basic Z-Shapes', () => {
|
||||
test('should connect cards through intermediate point', () => {
|
||||
test('should connect cards through two turns', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
// Block L-pattern possibilities
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 1, 3, 2);
|
||||
tester.placeCard(matrix, 3, 1, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Basic Z-pattern with intermediate point',
|
||||
'Basic Z-pattern with two turns',
|
||||
matrix,
|
||||
1, 1, 3, 3,
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should find multiple possible intermediate points', () => {
|
||||
test('should find path with distant cards', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 5, 5, 1);
|
||||
// Block L-pattern possibilities
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 1, 5, 2);
|
||||
tester.placeCard(matrix, 5, 1, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern with multiple intermediate points',
|
||||
'Z-pattern with distant cards',
|
||||
matrix,
|
||||
1, 1, 5, 5,
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should work with intermediate point at border', () => {
|
||||
test('should work with connecting column between cards', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 4, 4, 1);
|
||||
// Block L-pattern possibilities
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 2, 4, 2);
|
||||
tester.placeCard(matrix, 4, 2, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern with border intermediate point',
|
||||
'Z-pattern with connecting column',
|
||||
matrix,
|
||||
2, 2, 4, 4,
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Blocked Scenarios', () => {
|
||||
test('should fail when no intermediate point is available', () => {
|
||||
test('should fail when no path is available', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
// Block all possible intermediate points
|
||||
|
||||
// Block all possible paths
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
if (!((row === 1 && col === 1) || (row === 3 && col === 3))) {
|
||||
@@ -80,35 +80,35 @@ describe('Z-Pattern Tests', () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern blocked - no intermediate point',
|
||||
'Z-pattern blocked - no path available',
|
||||
matrix,
|
||||
1, 1, 3, 3,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should fail when paths to intermediate point are blocked', () => {
|
||||
test('should fail when all connecting columns and rows are blocked', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
// Block paths to potential intermediate points
|
||||
|
||||
// Block paths to potential connecting points
|
||||
tester.placeCard(matrix, 1, 2, 2);
|
||||
tester.placeCard(matrix, 2, 1, 2);
|
||||
tester.placeCard(matrix, 2, 3, 2);
|
||||
tester.placeCard(matrix, 3, 2, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern blocked - paths to intermediate blocked',
|
||||
'Z-pattern blocked - connecting paths blocked',
|
||||
matrix,
|
||||
1, 1, 3, 3,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -118,10 +118,10 @@ describe('Z-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 8, 20, 1);
|
||||
// Block simpler patterns
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 1, 20, 2);
|
||||
tester.placeCard(matrix, 8, 1, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern at board edges',
|
||||
matrix,
|
||||
@@ -129,74 +129,74 @@ describe('Z-Pattern Tests', () => {
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should handle Z-pattern along board boundaries', () => {
|
||||
test('should handle Z-pattern with same-row cards and blocker', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 2, 1);
|
||||
tester.placeCard(matrix, 1, 8, 1);
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 1, 5, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern along board boundary',
|
||||
'Z-pattern with same-row cards',
|
||||
matrix,
|
||||
1, 2, 1, 8,
|
||||
true,
|
||||
'Z-pattern'
|
||||
true
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Complex Intermediate Points', () => {
|
||||
test('should use specific intermediate point', () => {
|
||||
describe('Complex Connecting Points', () => {
|
||||
test('should use specific connecting column', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 6, 6, 1);
|
||||
// Block L-pattern possibilities
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 2, 6, 2);
|
||||
tester.placeCard(matrix, 6, 2, 2);
|
||||
// Ensure intermediate point at (4,4) is available
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern with specific intermediate point',
|
||||
'Z-pattern with specific connecting column',
|
||||
matrix,
|
||||
2, 2, 6, 6,
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should work in dense board with limited intermediate points', () => {
|
||||
test('should work in dense board with limited paths', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 4, 4, 1);
|
||||
|
||||
// Fill most of the board but leave some Z-pattern paths
|
||||
tester.placeCard(matrix, 2, 2, 1);
|
||||
tester.placeCard(matrix, 5, 5, 1);
|
||||
|
||||
// Fill most of the board but leave a Z-pattern corridor through col 3:
|
||||
// (2,2) -> (2,3) -> (5,3) -> (5,5)
|
||||
for (let row = 1; row <= 8; row++) {
|
||||
for (let col = 1; col <= 20; col++) {
|
||||
if (!((row === 1 && col === 1) || (row === 4 && col === 4) ||
|
||||
(row === 1 && col === 4) || (row === 4 && col === 1) ||
|
||||
(row === 2 && col === 2) || (row === 3 && col === 3))) {
|
||||
if (!((row === 2 && col === 2) || (row === 5 && col === 5) ||
|
||||
(row === 2 && col === 3) || (row === 5 && col === 3) ||
|
||||
(row === 3 && col === 3) || (row === 4 && col === 3) ||
|
||||
(row === 5 && col === 4))) {
|
||||
tester.placeCard(matrix, row, col, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern in dense board',
|
||||
matrix,
|
||||
1, 1, 4, 4,
|
||||
2, 2, 5, 5,
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -204,37 +204,35 @@ describe('Z-Pattern Tests', () => {
|
||||
describe('Same Row/Column Scenarios', () => {
|
||||
test('should handle Z-pattern with cards in same row', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 10, 1);
|
||||
tester.placeCard(matrix, 4, 1, 1);
|
||||
tester.placeCard(matrix, 4, 10, 1);
|
||||
// Block direct horizontal path
|
||||
tester.placeCard(matrix, 1, 5, 2);
|
||||
|
||||
tester.placeCard(matrix, 4, 5, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern with cards in same row',
|
||||
matrix,
|
||||
1, 1, 1, 10,
|
||||
true,
|
||||
'Z-pattern'
|
||||
4, 1, 4, 10,
|
||||
true
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should handle Z-pattern with cards in same column', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 6, 1, 1);
|
||||
tester.placeCard(matrix, 1, 5, 1);
|
||||
tester.placeCard(matrix, 6, 5, 1);
|
||||
// Block direct vertical path
|
||||
tester.placeCard(matrix, 3, 1, 2);
|
||||
|
||||
tester.placeCard(matrix, 3, 5, 2);
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern with cards in same column',
|
||||
matrix,
|
||||
1, 1, 6, 1,
|
||||
true,
|
||||
'Z-pattern'
|
||||
1, 5, 6, 5,
|
||||
true
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -244,7 +242,7 @@ describe('Z-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 1, 5, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Should prefer I-pattern over Z-pattern',
|
||||
matrix,
|
||||
@@ -252,7 +250,7 @@ describe('Z-Pattern Tests', () => {
|
||||
true,
|
||||
'I-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -260,7 +258,7 @@ describe('Z-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Should prefer L-pattern over Z-pattern',
|
||||
matrix,
|
||||
@@ -268,7 +266,7 @@ describe('Z-Pattern Tests', () => {
|
||||
true,
|
||||
'L-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -276,11 +274,10 @@ describe('Z-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 3, 3, 1);
|
||||
// Block I-pattern (not applicable)
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 1, 3, 2);
|
||||
tester.placeCard(matrix, 3, 1, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Should use Z-pattern when L-pattern blocked',
|
||||
matrix,
|
||||
@@ -288,7 +285,7 @@ describe('Z-Pattern Tests', () => {
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -301,7 +298,7 @@ describe('Z-Pattern Tests', () => {
|
||||
// Block L-pattern paths
|
||||
tester.placeCard(matrix, 1, 7, 2);
|
||||
tester.placeCard(matrix, 5, 1, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern with two distinct turns',
|
||||
matrix,
|
||||
@@ -309,26 +306,26 @@ describe('Z-Pattern Tests', () => {
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
test('should handle Z-pattern with intermediate point far from both cards', () => {
|
||||
test('should handle Z-pattern across full board', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 1, 1);
|
||||
tester.placeCard(matrix, 8, 20, 1);
|
||||
// Block other patterns by placing strategic obstacles
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 1, 20, 2);
|
||||
tester.placeCard(matrix, 8, 1, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern with distant intermediate point',
|
||||
'Z-pattern across full board',
|
||||
matrix,
|
||||
1, 1, 8, 20,
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
@@ -341,7 +338,7 @@ describe('Z-Pattern Tests', () => {
|
||||
// Block L-pattern
|
||||
tester.placeCard(matrix, 2, 8, 2);
|
||||
tester.placeCard(matrix, 6, 3, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Asymmetric Z-pattern',
|
||||
matrix,
|
||||
@@ -349,7 +346,7 @@ describe('Z-Pattern Tests', () => {
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
|
||||
@@ -357,10 +354,10 @@ describe('Z-Pattern Tests', () => {
|
||||
const matrix = tester.createEmptyMatrix();
|
||||
tester.placeCard(matrix, 1, 5, 1);
|
||||
tester.placeCard(matrix, 7, 15, 1);
|
||||
// Block other patterns
|
||||
// Block L-pattern corners
|
||||
tester.placeCard(matrix, 1, 15, 2);
|
||||
tester.placeCard(matrix, 7, 5, 2);
|
||||
|
||||
|
||||
const testCase = tester.createTestCase(
|
||||
'Z-pattern with varying distances',
|
||||
matrix,
|
||||
@@ -368,8 +365,8 @@ describe('Z-Pattern Tests', () => {
|
||||
true,
|
||||
'Z-pattern'
|
||||
);
|
||||
|
||||
|
||||
tester.expectTestCase(testCase);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user