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