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(randomness
) {
48 ChessRules
.GenRandInitFen(randomness
)
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(
66 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]),
71 getPotentialKingMoves(sq
) {
72 return super.getPotentialKnightMoves(sq
);
75 isAttacked(sq
, color
) {
77 this.isAttackedByCommoner(sq
, color
) ||
78 this.isAttackedByPawn(sq
, color
) ||
79 this.isAttackedByRook(sq
, color
) ||
80 this.isAttackedByBishop(sq
, color
) ||
81 this.isAttackedByQueen(sq
, color
) ||
82 this.isAttackedByKing(sq
, color
)
86 isAttackedByKing(sq
, color
) {
87 return this.isAttackedBySlideNJump(
96 isAttackedByCommoner(sq
, color
) {
97 return this.isAttackedBySlideNJump(
101 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]),
109 // NOTE: 4 next functions (almost) copy-paste from Spartan Chess
112 for (let i
=0; i
<8; i
++) {
113 for (let j
=0; j
<8; j
++) {
115 this.board
[i
][j
] != V
.EMPTY
&&
116 this.getColor(i
, j
) == color
&&
117 this.getPiece(i
, j
) == V
.KING
119 kings
.push({ x: i
, y: j
});
127 const color
= this.turn
;
128 const oppCol
= V
.GetOppCol(color
);
129 const kings
= this.getKingsPos(color
);
131 for (let i
of [0, 1]) {
133 kings
.length
>= i
+1 &&
134 this.isAttacked([kings
[i
].x
, kings
[i
].y
], oppCol
)
136 res
.push([kings
[i
].x
, kings
[i
].y
]);
143 if (moves
.length
== 0) return [];
144 const color
= moves
[0].vanish
[0].c
;
145 const oppCol
= V
.GetOppCol(color
);
146 // Check if both kings under attack.
147 // If yes, moves must remove at least one attack.
148 const kings
= this.getKingsPos(color
);
149 return moves
.filter(m
=> {
152 for (let k
of kings
) {
154 this.board
[k
.x
][k
.y
] == V
.EMPTY
155 ? [m
.appear
[0].x
, m
.appear
[0].y
] //king moved
157 if (this.isAttacked(curKingPos
, oppCol
)) attacks
++;
158 else break; //no need to check further
162 (kings
.length
== 2 && attacks
<= 1) ||
163 (kings
.length
== 1 && attacks
== 0)
169 if (super.atLeastOneMove()) return "*";
170 // Count kings on board
171 const color
= this.turn
;
172 const oppCol
= V
.GetOppCol(color
);
173 const kings
= this.getKingsPos(color
);
175 this.isAttacked([kings
[0].x
, kings
[0].y
], oppCol
) ||
176 (kings
.length
== 2 && this.isAttacked([kings
[1].x
, kings
[1].y
], oppCol
))
178 return (color
== 'w' ? "0-1" : "1-0");
180 return "1/2"; //stalemate
183 static get VALUES() {
187 c: 5, //the commoner is valuable