1 import { ChessRules
} from "@/base_rules";
3 export class MonochromeRules
extends ChessRules
{
4 static get HasEnpassant() {
5 // Pawns would be on the same side
9 static get HasFlags() {
14 return [ [[4, 0], [4, 8]] ];
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 for (let row
of rows
) {
27 for (let i
= 0; i
< row
.length
; i
++) {
28 if (V
.PIECES
.includes(row
[i
])) sumElts
++;
30 const num
= parseInt(row
[i
], 10);
31 if (isNaN(num
)) return false;
35 if (sumElts
!= V
.size
.y
) return false;
40 canIplay(side
, [x
, y
]) {
41 const xBounds
= side
== 'w' ? [4,7] : [0,3];
42 return this.turn
== side
&& x
>= xBounds
[0] && x
<= xBounds
[1];
45 canTake([x1
, y1
], [x2
, y2
]) {
46 // Capture in other half-board
47 return ((x1
<= 3 && x2
>= 4) || (x1
>= 4 && x2
<= 3));
50 // follow steps from x,y until something is met.
51 // if met piece is opponent and same movement (asA): eat it!
52 findCaptures_aux([x
, y
], asA
) {
56 ? [V
.QUEEN
, V
.KING
].includes(asA
)
57 ? V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
])
68 const oneStep
= [V
.KNIGHT
, V
.PAWN
, V
.KING
].includes(asA
);
69 outerLoop: for (let loop
= 0; loop
< steps
.length
; loop
++) {
70 const step
= steps
[loop
];
73 while (V
.OnBoard(i
, j
) && this.board
[i
][j
] == V
.EMPTY
) {
74 if (oneStep
) continue outerLoop
;
80 this.getPiece(i
, j
) == asA
&&
81 this.canTake([i
, j
], [x
, y
])
84 moves
.push(this.getBasicMove([x
, y
], [i
, j
]));
90 // Find possible captures from a square: look in every direction!
93 Array
.prototype.push
.apply(moves
, this.findCaptures_aux(sq
, V
.PAWN
));
94 Array
.prototype.push
.apply(moves
, this.findCaptures_aux(sq
, V
.ROOK
));
95 Array
.prototype.push
.apply(moves
, this.findCaptures_aux(sq
, V
.KNIGHT
));
96 Array
.prototype.push
.apply(moves
, this.findCaptures_aux(sq
, V
.BISHOP
));
97 Array
.prototype.push
.apply(moves
, this.findCaptures_aux(sq
, V
.QUEEN
));
98 Array
.prototype.push
.apply(moves
, this.findCaptures_aux(sq
, V
.KING
));
102 // Trim all non-capturing moves
103 static KeepCaptures(moves
) {
104 return moves
.filter(m
=> m
.vanish
.length
== 2);
107 getPotentialMovesFrom(sq
) {
108 const moves
= super.getPotentialMovesFrom(sq
);
109 const zenCaptures
= this.findCaptures(sq
);
110 // Remove duplicate captures in a lazy way (TODO: more efficient...)
113 if (m
.vanish
.length
== 2) {
115 m
.start
.x
+ "." + m
.start
.y
+ "." + m
.end
.x
+ "." + m
.end
.y
;
116 hashMoves
[hash
] = true;
119 return moves
.concat(zenCaptures
.filter(m
=> {
120 const hash
= m
.start
.x
+ "." + m
.start
.y
+ "." + m
.end
.x
+ "." + m
.end
.y
;
121 return !hashMoves
[hash
];
125 getAllPotentialMoves() {
126 const xBounds
= this.turn
== 'w' ? [4,7] : [0,3];
127 let potentialMoves
= [];
128 for (let i
= xBounds
[0]; i
<= xBounds
[1]; i
++) {
129 for (let j
= 0; j
< V
.size
.y
; j
++) {
130 if (this.board
[i
][j
] != V
.EMPTY
) {
131 Array
.prototype.push
.apply(
133 this.getPotentialMovesFrom([i
, j
])
138 if (potentialMoves
.some(m
=> m
.vanish
.length
== 2 && m
.appear
.length
== 1))
139 return V
.KeepCaptures(potentialMoves
);
140 return potentialMoves
;
144 const xBounds
= this.turn
== 'w' ? [4,7] : [0,3];
145 for (let i
= xBounds
[0]; i
<= xBounds
[1]; i
++) {
146 for (let j
= 0; j
< V
.size
.y
; j
++) {
148 this.board
[i
][j
] != V
.EMPTY
&&
149 this.getPotentialMovesFrom([i
, j
]).length
> 0
158 // Stop at the first capture found (if any)
159 atLeastOneCapture() {
160 const xBounds
= this.turn
== 'w' ? [4,7] : [0,3];
161 for (let i
= xBounds
[0]; i
<= xBounds
[1]; i
++) {
162 for (let j
= 0; j
< V
.size
.y
; j
++) {
164 this.board
[i
][j
] != V
.EMPTY
&&
165 this.getPotentialMovesFrom([i
, j
]).some(m
=> m
.vanish
.length
== 2)
174 getPossibleMovesFrom(sq
) {
175 let moves
= this.getPotentialMovesFrom(sq
);
176 const captureMoves
= V
.KeepCaptures(moves
);
177 if (captureMoves
.length
> 0) return captureMoves
;
178 if (this.atLeastOneCapture()) return [];
195 // Is there anything in opponent's half board?
196 const color
= V
.GetOppCol(this.turn
);
197 const xBounds
= color
== 'w' ? [4,7] : [0,3];
198 let nothingHere
= true;
199 outerLoop: for (let i
= xBounds
[0]; i
<= xBounds
[1]; i
++) {
200 for (let j
= 0; j
< V
.size
.y
; j
++) {
201 if (this.board
[i
][j
] != V
.EMPTY
) {
207 if (nothingHere
) return color
== 'w' ? "0-1" : "1-0";
208 if (this.atLeastOneMove()) return '*';
212 static GenRandInitFen(randomness
) {
213 // Remove the en-passant + castle part of the FEN
214 const fen
= ChessRules
.GenRandInitFen(randomness
).slice(0, -6);
215 const firstSpace
= fen
.indexOf(' ');
217 fen
.substr(0, firstSpace
).replace(/[A-Z]/g, (c
) => c
.toLowerCase()) +
218 fen
.substr(firstSpace
)
222 static get SEARCH_DEPTH() {
228 for (let i
= 0; i
< 8; i
++) {
229 for (let j
= 0; j
< V
.size
.y
; j
++) {
230 if (this.board
[i
][j
] != V
.EMPTY
) {
231 const sign
= (i
<= 3 ? -1 : 1);
232 // I don't think taking pieces' values into account would help
233 evaluation
+= sign
; //* V.VALUES[this.getPiece(i, j)];
241 // Translate initial square (because pieces may fly unusually!)
242 const initialSquare
= V
.CoordsToSquare(move.start
);
244 // Translate final square
245 const finalSquare
= V
.CoordsToSquare(move.end
);
248 const piece
= this.getPiece(move.start
.x
, move.start
.y
);
249 if (piece
== V
.PAWN
) {
250 // pawn move (TODO: enPassant indication)
251 if (move.vanish
.length
== 2) {
253 notation
= initialSquare
+ "x" + finalSquare
;
255 else notation
= finalSquare
;
256 if (piece
!= move.appear
[0].p
)
258 notation
+= "=" + move.appear
[0].p
.toUpperCase();
262 notation
= piece
.toUpperCase();
263 if (move.vanish
.length
> 1) notation
+= initialSquare
+ "x";
264 notation
+= finalSquare
;