c3277e9c34ee78b1a7c676f7b9b83caa10bb7625
[vchess.git] / client / src / variants / Suction.js
1 import { ChessRules, PiPo, Move } from "@/base_rules";
2
3 export class SuctionRules extends ChessRules {
4 static get PawnSpecs() {
5 return Object.assign(
6 {},
7 ChessRules.PawnSpecs,
8 // No promotions:
9 { promotions: [V.PAWN] }
10 );
11 }
12
13 static get HasFlags() {
14 return false;
15 }
16
17 setOtherVariables(fen) {
18 super.setOtherVariables(fen);
19 // Local stack of "captures"
20 this.cmoves = [];
21 const cmove = V.ParseFen(fen).cmove;
22 if (cmove == "-") this.cmoves.push(null);
23 else {
24 this.cmoves.push({
25 start: ChessRules.SquareToCoords(cmove.substr(0, 2)),
26 end: ChessRules.SquareToCoords(cmove.substr(2))
27 });
28 }
29 }
30
31 static ParseFen(fen) {
32 return Object.assign(
33 ChessRules.ParseFen(fen),
34 { cmove: fen.split(" ")[4] }
35 );
36 }
37
38 static IsGoodFen(fen) {
39 if (!ChessRules.IsGoodFen(fen)) return false;
40 const fenParts = fen.split(" ");
41 if (fenParts.length != 5) return false;
42 if (fenParts[4] != "-" && !fenParts[4].match(/^([a-h][1-8]){2}$/))
43 return false;
44 return true;
45 }
46
47 getCmove(move) {
48 if (move.vanish.length == 2)
49 return { start: move.start, end: move.end };
50 return null;
51 }
52
53 getBasicMove([sx, sy], [ex, ey]) {
54 const startColor = this.getColor(sx, sy);
55 const startPiece = this.getPiece(sx, sy);
56 let mv = new Move({
57 appear: [
58 new PiPo({
59 x: ex,
60 y: ey,
61 c: startColor,
62 p: startPiece
63 })
64 ],
65 vanish: [
66 new PiPo({
67 x: sx,
68 y: sy,
69 c: startColor,
70 p: startPiece
71 })
72 ]
73 });
74
75 if (this.board[ex][ey] != V.EMPTY) {
76 const endColor = this.getColor(ex, ey);
77 const endPiece = this.getPiece(ex, ey);
78 mv.vanish.push(
79 new PiPo({
80 x: ex,
81 y: ey,
82 c: endColor,
83 p: endPiece
84 })
85 );
86 mv.appear.push(
87 new PiPo({
88 x: sx,
89 y: sy,
90 c: endColor,
91 p: endPiece
92 })
93 );
94 }
95 return mv;
96 }
97
98 getEnpassantCaptures([x, y], shiftX) {
99 let moves = [];
100 const Lep = this.epSquares.length;
101 const epSquare = this.epSquares[Lep - 1]; //always at least one element
102 if (
103 !!epSquare &&
104 epSquare.x == x + shiftX &&
105 Math.abs(epSquare.y - y) == 1
106 ) {
107 let enpassantMove = this.getBasicMove([x, y], [epSquare.x, epSquare.y]);
108 const oppCol = V.GetOppCol(this.turn);
109 enpassantMove.vanish.push({
110 x: x,
111 y: epSquare.y,
112 p: "p",
113 c: oppCol
114 });
115 enpassantMove.appear.push({
116 x: x,
117 y: y,
118 p: "p",
119 c: oppCol
120 });
121 moves.push(enpassantMove);
122 }
123 return moves;
124 }
125
126 getPotentialKingMoves() {
127 return [];
128 }
129
130 // Does m2 un-do m1 ? (to disallow undoing captures)
131 oppositeMoves(m1, m2) {
132 return (
133 !!m1 &&
134 m2.vanish.length == 2 &&
135 m1.start.x == m2.start.x &&
136 m1.end.x == m2.end.x &&
137 m1.start.y == m2.start.y &&
138 m1.end.y == m2.end.y
139 );
140 }
141
142 filterValid(moves) {
143 if (moves.length == 0) return [];
144 const color = this.turn;
145 return moves.filter(m => {
146 const L = this.cmoves.length; //at least 1: init from FEN
147 return !this.oppositeMoves(this.cmoves[L - 1], m);
148 });
149 }
150
151 static GenRandInitFen(randomness) {
152 // Add empty cmove:
153 return ChessRules.GenRandInitFen(randomness).slice(0, -6) + "- -";
154 }
155
156 getCmoveFen() {
157 const L = this.cmoves.length;
158 return (
159 !this.cmoves[L - 1]
160 ? "-"
161 : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) +
162 ChessRules.CoordsToSquare(this.cmoves[L - 1].end)
163 );
164 }
165
166 getFen() {
167 return super.getFen() + " " + this.getCmoveFen();
168 }
169
170 getFenForRepeat() {
171 return super.getFenForRepeat() + "_" + this.getCmoveFen();
172 }
173
174 postPlay(move) {
175 super.postPlay(move);
176 if (move.vanish.length == 2) {
177 // Was opponent king swapped?
178 if (move.vanish[1].p == V.KING)
179 this.kingPos[this.turn] = [move.appear[1].x, move.appear[1].y];
180 }
181 this.cmoves.push(this.getCmove(move));
182 }
183
184 postUndo(move) {
185 super.postUndo(move);
186 if (move.appear.length == 2) {
187 if (move.appear[1].p == V.KING)
188 this.kingPos[move.vanish[1].c] = [move.vanish[1].x, move.vanish[1].y];
189 }
190 this.cmoves.pop();
191 }
192
193 atLeastOneMove() {
194 return true;
195 }
196
197 getCheckSquares() {
198 return [];
199 }
200
201 getCurrentScore() {
202 const color = this.turn;
203 const kp = this.kingPos[color];
204 if (color == "w" && kp[0] == 0) return "0-1";
205 if (color == "b" && kp[0] == V.size.x - 1) return "1-0";
206 // King is not on the opposite edge: game not over
207 return "*";
208 }
209
210 evalPosition() {
211 // Very simple criterion for now: kings position
212 return this.kingPos["w"][0] + this.kingPos["b"][0];
213 }
214
215 getNotation(move) {
216 // Translate final square
217 const finalSquare = V.CoordsToSquare(move.end);
218
219 const piece = this.getPiece(move.start.x, move.start.y);
220 if (piece == V.PAWN) {
221 // Pawn move
222 let notation = "";
223 if (move.vanish.length == 2) {
224 // Capture
225 const startColumn = V.CoordToColumn(move.start.y);
226 notation = startColumn + "x" + finalSquare;
227 }
228 else notation = finalSquare;
229 return notation;
230 }
231 // Piece movement
232 return (
233 piece.toUpperCase() +
234 (move.vanish.length == 2 ? "x" : "") +
235 finalSquare
236 );
237 }
238 };