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