Flip knights for variants with knightriders (waiting for a better image)
[vchess.git] / client / src / variants / Monochrome.js
CommitLineData
665eed90
BA
1import { ChessRules } from "@/base_rules";
2
3export class MonochromeRules extends ChessRules {
4 static get HasEnpassant() {
5 // Pawns would be on the same side
6 return false;
7 }
8
8ca6042e
BA
9 static get HasFlags() {
10 return false;
11 }
12
ad030c7d
BA
13 static get Lines() {
14 return [ [[4, 0], [4, 8]] ];
15 }
16
5246b49d
BA
17 get showFirstTurn() {
18 return true;
19 }
20
665eed90
BA
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) {
26 let sumElts = 0;
27 for (let i = 0; i < row.length; i++) {
28 if (V.PIECES.includes(row[i])) sumElts++;
29 else {
e50a8025 30 const num = parseInt(row[i], 10);
665eed90
BA
31 if (isNaN(num)) return false;
32 sumElts += num;
33 }
34 }
35 if (sumElts != V.size.y) return false;
36 }
37 return true;
38 }
39
306dab5f
BA
40 getPpath(b) {
41 return (b[1] == V.KNIGHT ? "Enpassant/" : "") + b;
42 }
43
665eed90
BA
44 canIplay(side, [x, y]) {
45 const xBounds = side == 'w' ? [4,7] : [0,3];
46 return this.turn == side && x >= xBounds[0] && x <= xBounds[1];
47 }
48
49 canTake([x1, y1], [x2, y2]) {
50 // Capture in other half-board
51 return ((x1 <= 3 && x2 >= 4) || (x1 >= 4 && x2 <= 3));
52 }
53
54 // Trim all non-capturing moves
55 static KeepCaptures(moves) {
8ca6042e
BA
56 return moves.filter(m => m.vanish.length == 2);
57 }
58
f9ecc499
BA
59 getPotentialKnightMoves(sq) {
60 // Knight becomes knightrider:
61 return this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT]);
62 }
63
64 getPotentialKingMoves(sq) {
65 // King become queen:
66 return (
0fbe4ffa
BA
67 this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]))
68 );
665eed90
BA
69 }
70
71 getAllPotentialMoves() {
72 const xBounds = this.turn == 'w' ? [4,7] : [0,3];
73 let potentialMoves = [];
74 for (let i = xBounds[0]; i <= xBounds[1]; i++) {
75 for (let j = 0; j < V.size.y; j++) {
76 if (this.board[i][j] != V.EMPTY) {
77 Array.prototype.push.apply(
78 potentialMoves,
79 this.getPotentialMovesFrom([i, j])
80 );
81 }
82 }
83 }
84 if (potentialMoves.some(m => m.vanish.length == 2 && m.appear.length == 1))
85 return V.KeepCaptures(potentialMoves);
86 return potentialMoves;
87 }
88
89 atLeastOneMove() {
90 const xBounds = this.turn == 'w' ? [4,7] : [0,3];
91 for (let i = xBounds[0]; i <= xBounds[1]; i++) {
92 for (let j = 0; j < V.size.y; j++) {
93 if (
94 this.board[i][j] != V.EMPTY &&
95 this.getPotentialMovesFrom([i, j]).length > 0
96 ) {
97 return true;
98 }
99 }
100 }
101 return false;
102 }
103
104 // Stop at the first capture found (if any)
105 atLeastOneCapture() {
106 const xBounds = this.turn == 'w' ? [4,7] : [0,3];
107 for (let i = xBounds[0]; i <= xBounds[1]; i++) {
108 for (let j = 0; j < V.size.y; j++) {
109 if (
110 this.board[i][j] != V.EMPTY &&
8ca6042e 111 this.getPotentialMovesFrom([i, j]).some(m => m.vanish.length == 2)
665eed90
BA
112 ) {
113 return true;
114 }
115 }
116 }
117 return false;
118 }
119
120 getPossibleMovesFrom(sq) {
121 let moves = this.getPotentialMovesFrom(sq);
122 const captureMoves = V.KeepCaptures(moves);
123 if (captureMoves.length > 0) return captureMoves;
124 if (this.atLeastOneCapture()) return [];
125 return moves;
126 }
127
128 filterValid(moves) {
129 return moves;
130 }
131
132 isAttacked() {
133 return false;
134 }
135
136 getCheckSquares() {
137 return [];
138 }
139
140 getCurrentScore() {
8ca6042e 141 // Is there anything in opponent's half board?
665eed90
BA
142 const color = V.GetOppCol(this.turn);
143 const xBounds = color == 'w' ? [4,7] : [0,3];
144 let nothingHere = true;
145 outerLoop: for (let i = xBounds[0]; i <= xBounds[1]; i++) {
146 for (let j = 0; j < V.size.y; j++) {
147 if (this.board[i][j] != V.EMPTY) {
148 nothingHere = false;
149 break outerLoop;
150 }
151 }
152 }
153 if (nothingHere) return color == 'w' ? "0-1" : "1-0";
154 if (this.atLeastOneMove()) return '*';
155 return "1/2";
156 }
157
158 static GenRandInitFen(randomness) {
8ca6042e 159 // Remove the en-passant + castle part of the FEN
0fbe4ffa 160 let fen = ChessRules.GenRandInitFen(randomness).slice(0, -6);
306dab5f
BA
161 // Replace kings with queens
162 fen = fen.replace("k", "q").replace("K", "Q");
0fbe4ffa
BA
163 // Move pawns up:
164 fen = fen.replace("pppppppp/8","8/pppppppp")
165 .replace("8/PPPPPPPP","PPPPPPPP/8");
665eed90 166 const firstSpace = fen.indexOf(' ');
0fbe4ffa
BA
167 // Paint it black:
168 fen =
665eed90 169 fen.substr(0, firstSpace).replace(/[A-Z]/g, (c) => c.toLowerCase()) +
0fbe4ffa
BA
170 fen.substr(firstSpace);
171 return fen;
665eed90
BA
172 }
173
174 static get SEARCH_DEPTH() {
175 return 4;
176 }
177
178 evalPosition() {
179 let evaluation = 0;
180 for (let i = 0; i < 8; i++) {
181 for (let j = 0; j < V.size.y; j++) {
182 if (this.board[i][j] != V.EMPTY) {
183 const sign = (i <= 3 ? -1 : 1);
184 // I don't think taking pieces' values into account would help
185 evaluation += sign; //* V.VALUES[this.getPiece(i, j)];
186 }
187 }
188 }
189 return evaluation;
190 }
8ca6042e
BA
191
192 getNotation(move) {
193 // Translate initial square (because pieces may fly unusually!)
194 const initialSquare = V.CoordsToSquare(move.start);
195
196 // Translate final square
197 const finalSquare = V.CoordsToSquare(move.end);
198
199 let notation = "";
200 const piece = this.getPiece(move.start.x, move.start.y);
201 if (piece == V.PAWN) {
202 // pawn move (TODO: enPassant indication)
203 if (move.vanish.length == 2) {
204 // capture
205 notation = initialSquare + "x" + finalSquare;
206 }
207 else notation = finalSquare;
208 if (piece != move.appear[0].p)
209 //promotion
210 notation += "=" + move.appear[0].p.toUpperCase();
211 }
212 else {
213 // Piece movement
214 notation = piece.toUpperCase();
215 if (move.vanish.length > 1) notation += initialSquare + "x";
216 notation += finalSquare;
217 }
218 return notation;
219 }
665eed90 220};