Simplify Monster + Doublemove2. Smoother example games
[vchess.git] / client / src / variants / Suction.js
CommitLineData
31e9e40a
BA
1import { ChessRules, PiPo, Move } from "@/base_rules";
2
32f6285e 3export class SuctionRules extends ChessRules {
2ac5c764
BA
4 static get PawnSpecs() {
5 return Object.assign(
6 {},
7 ChessRules.PawnSpecs,
8 // No promotions:
9 { promotions: [V.PAWN] }
10 );
11 }
12
3a2a7b5f
BA
13 static get HasFlags() {
14 return false;
15 }
16
241bf8f2
BA
17 setOtherVariables(fen) {
18 super.setOtherVariables(fen);
3a2a7b5f 19 // Local stack of "captures"
241bf8f2 20 this.cmoves = [];
3a2a7b5f 21 const cmove = V.ParseFen(fen).cmove;
241bf8f2
BA
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
3a2a7b5f 31 static ParseFen(fen) {
6f2f9437
BA
32 return Object.assign(
33 ChessRules.ParseFen(fen),
34 { cmove: fen.split(" ")[4] }
35 );
3a2a7b5f
BA
36 }
37
241bf8f2
BA
38 static IsGoodFen(fen) {
39 if (!ChessRules.IsGoodFen(fen)) return false;
40 const fenParts = fen.split(" ");
61656127
BA
41 if (fenParts.length != 5) return false;
42 if (fenParts[4] != "-" && !fenParts[4].match(/^([a-h][1-8]){2}$/))
241bf8f2
BA
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
31e9e40a
BA
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
32f6285e 98 getEnpassantCaptures([x, y], shiftX) {
31e9e40a 99 let moves = [];
31e9e40a
BA
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]);
58bf4670 108 const oppCol = V.GetOppCol(this.turn);
31e9e40a
BA
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 }
31e9e40a
BA
123 return moves;
124 }
125
126 getPotentialKingMoves() {
127 return [];
128 }
129
241bf8f2
BA
130 // Does m2 un-do m1 ? (to disallow undoing captures)
131 oppositeMoves(m1, m2) {
132 return (
61656127 133 !!m1 &&
241bf8f2
BA
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
7ba4a5bc 151 static GenRandInitFen(randomness) {
241bf8f2 152 // Add empty cmove:
3a2a7b5f 153 return ChessRules.GenRandInitFen(randomness).slice(0, -6) + "- -";
31e9e40a
BA
154 }
155
2f8dce6a 156 getCmoveFen() {
241bf8f2 157 const L = this.cmoves.length;
2f8dce6a
BA
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();
241bf8f2
BA
172 }
173
3a2a7b5f
BA
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 }
241bf8f2 181 this.cmoves.push(this.getCmove(move));
241bf8f2
BA
182 }
183
3a2a7b5f
BA
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 }
241bf8f2 190 this.cmoves.pop();
241bf8f2
BA
191 }
192
193 atLeastOneMove() {
194 return true;
31e9e40a
BA
195 }
196
197 getCheckSquares() {
198 return [];
199 }
200
201 getCurrentScore() {
202 const color = this.turn;
203 const kp = this.kingPos[color];
bb688df5
BA
204 if (color == "w" && kp[0] == 0) return "0-1";
205 if (color == "b" && kp[0] == V.size.x - 1) return "1-0";
31e9e40a
BA
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 }
71ef1664
BA
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 }
31e9e40a 238};