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