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