Draft Ball variant + some fixes, enhancements and code cleaning
[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 HasFlags() {
5 return false;
6 }
7
8 setOtherVariables(fen) {
9 super.setOtherVariables(fen);
10 // Local stack of "captures"
11 this.cmoves = [];
12 const cmove = V.ParseFen(fen).cmove;
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
22 static ParseFen(fen) {
23 return Object.assign(
24 ChessRules.ParseFen(fen),
25 { cmove: fen.split(" ")[4] }
26 );
27 }
28
29 static IsGoodFen(fen) {
30 if (!ChessRules.IsGoodFen(fen)) return false;
31 const fenParts = fen.split(" ");
32 if (fenParts.length != 6) return false;
33 if (fenParts[5] != "-" && !fenParts[5].match(/^([a-h][1-8]){2}$/))
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
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
89 getEnpassantCaptures([x, y], shiftX) {
90 let moves = [];
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]);
99 const oppCol = V.GetOppCol(color);
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 }
114 return moves;
115 }
116
117 getPotentialKingMoves() {
118 return [];
119 }
120
121 // Does m2 un-do m1 ? (to disallow undoing captures)
122 oppositeMoves(m1, m2) {
123 return (
124 m1 &&
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
142 static GenRandInitFen(randomness) {
143 // Add empty cmove:
144 return ChessRules.GenRandInitFen(randomness).slice(0, -6) + "- -";
145 }
146
147 getFen() {
148 const L = this.cmoves.length;
149 const cmoveFen = !this.cmoves[L - 1]
150 ? "-"
151 : ChessRules.CoordsToSquare(this.cmoves[L - 1].start) +
152 ChessRules.CoordsToSquare(this.cmoves[L - 1].end);
153 return super.getFen() + " " + cmoveFen;
154 }
155
156 postPlay(move) {
157 super.postPlay(move);
158 if (move.vanish.length == 2) {
159 // Was opponent king swapped?
160 if (move.vanish[1].p == V.KING)
161 this.kingPos[this.turn] = [move.appear[1].x, move.appear[1].y];
162 }
163 this.cmoves.push(this.getCmove(move));
164 }
165
166 postUndo(move) {
167 super.postUndo(move);
168 if (move.appear.length == 2) {
169 if (move.appear[1].p == V.KING)
170 this.kingPos[move.vanish[1].c] = [move.vanish[1].x, move.vanish[1].y];
171 }
172 this.cmoves.pop();
173 }
174
175 atLeastOneMove() {
176 return true;
177 }
178
179 getCheckSquares() {
180 return [];
181 }
182
183 getCurrentScore() {
184 const color = this.turn;
185 const kp = this.kingPos[color];
186 if (color == "w" && kp[0] == 0) return "0-1";
187 if (color == "b" && kp[0] == V.size.x - 1) return "1-0";
188 // King is not on the opposite edge: game not over
189 return "*";
190 }
191
192 evalPosition() {
193 // Very simple criterion for now: kings position
194 return this.kingPos["w"][0] + this.kingPos["b"][0];
195 }
196
197 getNotation(move) {
198 // Translate final square
199 const finalSquare = V.CoordsToSquare(move.end);
200
201 const piece = this.getPiece(move.start.x, move.start.y);
202 if (piece == V.PAWN) {
203 // Pawn move
204 let notation = "";
205 if (move.vanish.length == 2) {
206 // Capture
207 const startColumn = V.CoordToColumn(move.start.y);
208 notation = startColumn + "x" + finalSquare;
209 }
210 else notation = finalSquare;
211 return notation;
212 }
213 // Piece movement
214 return (
215 piece.toUpperCase() +
216 (move.vanish.length == 2 ? "x" : "") +
217 finalSquare
218 );
219 }
220 };