1 import { ChessRules
} from "@/base_rules";
3 export class Knightmate2Rules
extends ChessRules
{
5 static get HasFlags() {
9 static get COMMONER() {
14 return ChessRules
.PIECES
.concat([V
.COMMONER
]);
18 return ([V
.KING
, V
.COMMONER
].includes(b
[1]) ? "Knightmate/" : "") + b
;
21 static IsGoodPosition(position
) {
22 if (position
.length
== 0) return false;
23 const rows
= position
.split("/");
24 if (rows
.length
!= V
.size
.x
) return false;
25 let kings
= { "k": 0, "K": 0 };
26 for (let row
of rows
) {
28 for (let i
= 0; i
< row
.length
; i
++) {
29 if (['K','k'].includes(row
[i
])) kings
[row
[i
]]++;
30 if (V
.PIECES
.includes(row
[i
].toLowerCase())) sumElts
++;
32 const num
= parseInt(row
[i
], 10);
33 if (isNaN(num
) || num
<= 0) return false;
37 if (sumElts
!= V
.size
.y
) return false;
39 // 1 or 2 kings should be on board.
40 if (Object
.values(kings
).some(k
=> ![1, 2].includes(k
))) return false;
46 static GenRandInitFen(options
) {
48 ChessRules
.GenRandInitFen(options
)
49 .replace(/k
/g
, 'c').replace(/K
/g
, 'C')
50 .replace(/n
/g
, 'k').replace(/N
/g
, 'K')
54 getPotentialMovesFrom([x
, y
]) {
55 switch (this.getPiece(x
, y
)) {
57 return this.getPotentialCommonerMoves([x
, y
]);
59 return super.getPotentialMovesFrom([x
, y
]);
63 getPotentialCommonerMoves(sq
) {
64 return this.getSlideNJumpMoves(
65 sq
, V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1);
68 getPotentialKingMoves(sq
) {
69 return super.getPotentialKnightMoves(sq
);
72 isAttacked(sq
, color
) {
74 this.isAttackedByCommoner(sq
, color
) ||
75 this.isAttackedByPawn(sq
, color
) ||
76 this.isAttackedByRook(sq
, color
) ||
77 this.isAttackedByBishop(sq
, color
) ||
78 this.isAttackedByQueen(sq
, color
) ||
79 this.isAttackedByKing(sq
, color
)
83 isAttackedByKing(sq
, color
) {
84 return this.isAttackedBySlideNJump(
85 sq
, color
, V
.KING
, V
.steps
[V
.KNIGHT
], 1);
88 isAttackedByCommoner(sq
, color
) {
89 return this.isAttackedBySlideNJump(
90 sq
, color
, V
.COMMONER
, V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]), 1);
96 // NOTE: 4 next functions (almost) copy-paste from Spartan Chess
99 for (let i
=0; i
<8; i
++) {
100 for (let j
=0; j
<8; j
++) {
102 this.board
[i
][j
] != V
.EMPTY
&&
103 this.getColor(i
, j
) == color
&&
104 this.getPiece(i
, j
) == V
.KING
106 kings
.push({ x: i
, y: j
});
114 const color
= this.turn
;
115 const oppCol
= V
.GetOppCol(color
);
116 const kings
= this.getKingsPos(color
);
118 for (let i
of [0, 1]) {
120 kings
.length
>= i
+1 &&
121 this.isAttacked([kings
[i
].x
, kings
[i
].y
], oppCol
)
123 res
.push([kings
[i
].x
, kings
[i
].y
]);
130 if (moves
.length
== 0) return [];
131 const color
= moves
[0].vanish
[0].c
;
132 const oppCol
= V
.GetOppCol(color
);
133 // Check if both kings under attack.
134 // If yes, moves must remove at least one attack.
135 const kings
= this.getKingsPos(color
);
136 return moves
.filter(m
=> {
139 for (let k
of kings
) {
141 this.board
[k
.x
][k
.y
] == V
.EMPTY
142 ? [m
.appear
[0].x
, m
.appear
[0].y
] //king moved
144 if (this.isAttacked(curKingPos
, oppCol
)) attacks
++;
145 else break; //no need to check further
149 (kings
.length
== 2 && attacks
<= 1) ||
150 (kings
.length
== 1 && attacks
== 0)
156 if (super.atLeastOneMove()) return "*";
157 // Count kings on board
158 const color
= this.turn
;
159 const oppCol
= V
.GetOppCol(color
);
160 const kings
= this.getKingsPos(color
);
162 this.isAttacked([kings
[0].x
, kings
[0].y
], oppCol
) ||
163 (kings
.length
== 2 && this.isAttacked([kings
[1].x
, kings
[1].y
], oppCol
))
165 return (color
== 'w' ? "0-1" : "1-0");
167 return "1/2"; //stalemate
170 static get VALUES() {
174 c: 5, //the commoner is valuable