Started code review + some fixes (unfinished)
[vchess.git] / client / src / variants / Losers.js
CommitLineData
0c3fe8a6
BA
1import { ChessRules } from "@/base_rules";
2import { ArrayFun } from "@/utils/array";
3import { randInt } from "@/utils/alea";
4
6808d7a1
BA
5export const VariantRules = class LosersRules extends ChessRules {
6 static get HasFlags() {
7 return false;
8 }
dac39588 9
6808d7a1
BA
10 getPotentialPawnMoves([x, y]) {
11 let moves = super.getPotentialPawnMoves([x, y]);
dac39588
BA
12
13 // Complete with promotion(s) into king, if possible
14 const color = this.turn;
6808d7a1
BA
15 const shift = color == "w" ? -1 : 1;
16 const lastRank = color == "w" ? 0 : V.size.x - 1;
17 if (x + shift == lastRank) {
dac39588 18 // Normal move
6808d7a1
BA
19 if (this.board[x + shift][y] == V.EMPTY)
20 moves.push(
21 this.getBasicMove([x, y], [x + shift, y], { c: color, p: V.KING })
22 );
dac39588 23 // Captures
6808d7a1
BA
24 if (
25 y > 0 &&
26 this.canTake([x, y], [x + shift, y - 1]) &&
27 this.board[x + shift][y - 1] != V.EMPTY
28 ) {
29 moves.push(
30 this.getBasicMove([x, y], [x + shift, y - 1], { c: color, p: V.KING })
31 );
dac39588 32 }
6808d7a1
BA
33 if (
34 y < V.size.y - 1 &&
35 this.canTake([x, y], [x + shift, y + 1]) &&
36 this.board[x + shift][y + 1] != V.EMPTY
37 ) {
38 moves.push(
39 this.getBasicMove([x, y], [x + shift, y + 1], { c: color, p: V.KING })
40 );
dac39588
BA
41 }
42 }
43
44 return moves;
45 }
46
6808d7a1 47 getPotentialKingMoves(sq) {
dac39588 48 // No castle:
6808d7a1
BA
49 return this.getSlideNJumpMoves(
50 sq,
51 V.steps[V.ROOK].concat(V.steps[V.BISHOP]),
52 "oneStep"
53 );
dac39588
BA
54 }
55
56 // Stop at the first capture found (if any)
6808d7a1 57 atLeastOneCapture() {
dac39588
BA
58 const color = this.turn;
59 const oppCol = V.GetOppCol(color);
6808d7a1
BA
60 for (let i = 0; i < V.size.x; i++) {
61 for (let j = 0; j < V.size.y; j++) {
62 if (this.board[i][j] != V.EMPTY && this.getColor(i, j) != oppCol) {
63 const moves = this.getPotentialMovesFrom([i, j]);
64 if (moves.length > 0) {
65 for (let k = 0; k < moves.length; k++) {
66 if (
67 moves[k].vanish.length == 2 &&
68 this.filterValid([moves[k]]).length > 0
69 )
dac39588
BA
70 return true;
71 }
72 }
73 }
74 }
75 }
76 return false;
77 }
78
79 // Trim all non-capturing moves
6808d7a1
BA
80 static KeepCaptures(moves) {
81 return moves.filter(m => {
82 return m.vanish.length == 2;
83 });
dac39588
BA
84 }
85
6808d7a1
BA
86 getPossibleMovesFrom(sq) {
87 let moves = this.filterValid(this.getPotentialMovesFrom(sq));
dac39588 88 // This is called from interface: we need to know if a capture is possible
6808d7a1 89 if (this.atLeastOneCapture()) moves = V.KeepCaptures(moves);
dac39588
BA
90 return moves;
91 }
92
6808d7a1 93 getAllValidMoves() {
dac39588 94 let moves = super.getAllValidMoves();
6808d7a1
BA
95 if (
96 moves.some(m => {
97 return m.vanish.length == 2;
98 })
99 )
dac39588
BA
100 moves = V.KeepCaptures(moves);
101 return moves;
102 }
103
6808d7a1 104 underCheck() {
dac39588
BA
105 return false; //No notion of check
106 }
107
6808d7a1 108 getCheckSquares() {
dac39588
BA
109 return [];
110 }
111
112 // No variables update because no royal king + no castling
6808d7a1
BA
113 updateVariables() {}
114 unupdateVariables() {}
a6abf094 115
6808d7a1
BA
116 getCurrentScore() {
117 if (this.atLeastOneMove())
118 // game not over
0c3fe8a6
BA
119 return "*";
120
121 // No valid move: the side who cannot move wins
6808d7a1 122 return this.turn == "w" ? "1-0" : "0-1";
dac39588
BA
123 }
124
6808d7a1 125 static get VALUES() {
dac39588
BA
126 // Experimental...
127 return {
6808d7a1
BA
128 p: 1,
129 r: 7,
130 n: 3,
131 b: 3,
132 q: 5,
133 k: 5
dac39588
BA
134 };
135 }
136
6808d7a1
BA
137 static get SEARCH_DEPTH() {
138 return 4;
139 }
dac39588 140
6808d7a1
BA
141 evalPosition() {
142 return -super.evalPosition(); //better with less material
dac39588
BA
143 }
144
6808d7a1
BA
145 static GenRandInitFen() {
146 let pieces = { w: new Array(8), b: new Array(8) };
dac39588 147 // Shuffle pieces on first and last rank
6808d7a1 148 for (let c of ["w", "b"]) {
dac39588
BA
149 let positions = ArrayFun.range(8);
150
151 // Get random squares for bishops
152 let randIndex = 2 * randInt(4);
153 let bishop1Pos = positions[randIndex];
154 // The second bishop must be on a square of different color
155 let randIndex_tmp = 2 * randInt(4) + 1;
156 let bishop2Pos = positions[randIndex_tmp];
157 // Remove chosen squares
6808d7a1
BA
158 positions.splice(Math.max(randIndex, randIndex_tmp), 1);
159 positions.splice(Math.min(randIndex, randIndex_tmp), 1);
dac39588
BA
160
161 // Get random squares for knights
162 randIndex = randInt(6);
163 let knight1Pos = positions[randIndex];
164 positions.splice(randIndex, 1);
165 randIndex = randInt(5);
166 let knight2Pos = positions[randIndex];
167 positions.splice(randIndex, 1);
168
169 // Get random square for queen
170 randIndex = randInt(4);
171 let queenPos = positions[randIndex];
172 positions.splice(randIndex, 1);
173
174 // Random square for king (no castle)
175 randIndex = randInt(3);
176 let kingPos = positions[randIndex];
177 positions.splice(randIndex, 1);
178
179 // Rooks positions are now fixed
180 let rook1Pos = positions[0];
181 let rook2Pos = positions[1];
182
183 // Finally put the shuffled pieces in the board array
6808d7a1
BA
184 pieces[c][rook1Pos] = "r";
185 pieces[c][knight1Pos] = "n";
186 pieces[c][bishop1Pos] = "b";
187 pieces[c][queenPos] = "q";
188 pieces[c][kingPos] = "k";
189 pieces[c][bishop2Pos] = "b";
190 pieces[c][knight2Pos] = "n";
191 pieces[c][rook2Pos] = "r";
dac39588 192 }
6808d7a1
BA
193 return (
194 pieces["b"].join("") +
dac39588
BA
195 "/pppppppp/8/8/8/8/PPPPPPPP/" +
196 pieces["w"].join("").toUpperCase() +
6808d7a1
BA
197 " w 0 -"
198 ); //en-passant allowed, but no flags
dac39588 199 }
6808d7a1 200};