A few fixes + draft Interweave and Takenmake. Only 1 1/2 variant to go now :)
[vchess.git] / client / src / variants / Takenmake.js
1 import { ChessRules } from "@/base_rules";
2
3 export class TakenmakeRules extends ChessRules {
4 setOtherVariables(fen) {
5 super.setOtherVariables(fen);
6 // Stack of "last move" only for intermediate captures
7 this.lastMoveEnd = [null];
8 }
9
10 getPotentialMovesFrom([x, y], asA) {
11 const L = this.lastMoveEnd.length;
12 if (!asA && !!this.lastMoveEnd[L-1]) {
13 asA = this.lastMoveEnd[L-1].p;
14 if (x != this.lastMoveEnd[L-1].x || y != this.lastMoveEnd[L-1].y) {
15 // A capture was played: wrong square
16 return [];
17 }
18 }
19 let moves = [];
20 const piece = this.getPiece(x, y);
21 switch (asA || piece) {
22 case V.PAWN:
23 if (!asA || piece == V.PAWN)
24 moves = this.getPotentialPawnMoves([x, y]);
25 else {
26 // Special case: we don't want promotion, since just moving like
27 // a pawn, but I'm in fact not a pawn :)
28 const shiftX = (this.turn == 'w' ? -1 : 1);
29 if (this.board[x + shiftX][y] == V.EMPTY)
30 moves = [this.getBasicMove([x, y], [x + shiftX, y])];
31 }
32 break;
33 case V.ROOK:
34 moves = this.getPotentialRookMoves([x, y]);
35 break;
36 case V.KNIGHT:
37 moves = this.getPotentialKnightMoves([x, y]);
38 break;
39 case V.BISHOP:
40 moves = this.getPotentialBishopMoves([x, y]);
41 break;
42 case V.KING:
43 moves = this.getPotentialKingMoves([x, y]);
44 break;
45 case V.QUEEN:
46 moves = this.getPotentialQueenMoves([x, y]);
47 break;
48 }
49 // Post-process: if capture,
50 // can a move "as-capturer" be achieved with the same piece?
51 if (!asA) {
52 const color = this.turn;
53 return moves.filter(m => {
54 if (m.vanish.length == 2 && m.appear.length == 1) {
55 this.play(m);
56 let moveOk = true;
57 const makeMoves =
58 this.getPotentialMovesFrom([m.end.x, m.end.y], m.vanish[1].p);
59 if (
60 makeMoves.every(mm => {
61 // Cannot castle after a capturing move
62 // (with the capturing piece):
63 if (mm.vanish.length == 2) return true;
64 this.play(mm);
65 const res = this.underCheck(color);
66 this.undo(mm);
67 return res;
68 })
69 ) {
70 moveOk = false;
71 }
72 this.undo(m);
73 return moveOk;
74 }
75 return true;
76 });
77 }
78 // Moving "as a": filter out captures (no castles here)
79 return moves.filter(m => m.vanish.length == 1);
80 }
81
82 getPossibleMovesFrom(sq) {
83 const L = this.lastMoveEnd.length;
84 let asA = undefined;
85 if (!!this.lastMoveEnd[L-1]) {
86 if (
87 sq[0] != this.lastMoveEnd[L-1].x ||
88 sq[1] != this.lastMoveEnd[L-1].y
89 ) {
90 return [];
91 }
92 asA = this.lastMoveEnd[L-1].p;
93 }
94 return this.filterValid(this.getPotentialMovesFrom(sq, asA));
95 }
96
97 filterValid(moves) {
98 let noCaptureMoves = [];
99 let captureMoves = [];
100 moves.forEach(m => {
101 if (m.vanish.length == 1 || m.appear.length == 2) noCaptureMoves.push(m);
102 else captureMoves.push(m);
103 });
104 // Capturing moves were already checked in getPotentialMovesFrom()
105 return super.filterValid(noCaptureMoves).concat(captureMoves);
106 }
107
108 play(move) {
109 move.flags = JSON.stringify(this.aggregateFlags());
110 this.epSquares.push(this.getEpSquare(move));
111 V.PlayOnBoard(this.board, move);
112 if (move.vanish.length == 1 || move.appear.length == 2) {
113 // Not a capture: change turn
114 this.turn = V.GetOppCol(this.turn);
115 this.movesCount++;
116 this.lastMoveEnd.push(null);
117 }
118 else {
119 this.lastMoveEnd.push(
120 Object.assign({}, move.end, { p: move.vanish[1].p })
121 );
122 }
123 this.postPlay(move);
124 }
125
126 postPlay(move) {
127 const c = move.vanish[0].c;
128 const piece = move.vanish[0].p;
129 if (piece == V.KING && move.appear.length > 0) {
130 this.kingPos[c][0] = move.appear[0].x;
131 this.kingPos[c][1] = move.appear[0].y;
132 }
133 super.updateCastleFlags(move, piece);
134 }
135
136 undo(move) {
137 this.disaggregateFlags(JSON.parse(move.flags));
138 this.epSquares.pop();
139 this.lastMoveEnd.pop();
140 V.UndoOnBoard(this.board, move);
141 if (move.vanish.length == 1 || move.appear.length == 2) {
142 this.turn = V.GetOppCol(this.turn);
143 this.movesCount--;
144 }
145 super.postUndo(move);
146 }
147 };