04bb110c0489ad3f56ae2abdc9d61aafa8da1fce
[vchess.git] / public / javascripts / variants / Switching.js
1 class SwitchingRules extends ChessRules
2 {
3 // Build switch move between squares x1,y1 and x2,y2
4 getSwitchMove_s([x1,y1],[x2,y2])
5 {
6 const c = this.getColor(x1,y1); //same as color at square 2
7 const p1 = this.getPiece(x1,y1);
8 const p2 = this.getPiece(x2,y2);
9 if (p1 == V.KING && p2 == V.ROOK)
10 return []; //avoid duplicate moves (potential conflict with castle)
11 let move = new Move({
12 appear: [
13 new PiPo({x:x2,y:y2,c:c,p:p1}),
14 new PiPo({x:x1,y:y1,c:c,p:p2})
15 ],
16 vanish: [
17 new PiPo({x:x1,y:y1,c:c,p:p1}),
18 new PiPo({x:x2,y:y2,c:c,p:p2})
19 ],
20 start: {x:x1,y:y1},
21 end: {x:x2,y:y2}
22 });
23 // Move completion: promote switched pawns (as in Magnetic)
24 const lastRank = (c == "w" ? 0 : V.size.x-1);
25 let moves = [];
26 if ((p1==V.PAWN && x2==lastRank) || (p2==V.PAWN && x1==lastRank))
27 {
28 const idx = (p1==V.PAWN ? 0 : 1);
29 move.appear[idx].p = V.ROOK;
30 moves.push(move);
31 for (let piece of [V.KNIGHT, V.BISHOP, V.QUEEN])
32 {
33 let cmove = JSON.parse(JSON.stringify(move));
34 cmove.appear[idx].p = piece;
35 moves.push(cmove);
36 }
37 if (idx == 1)
38 {
39 // Swap moves[i].appear[0] and [1] for moves presentation [TODO...]
40 moves.forEach(m => {
41 let tmp = m.appear[0];
42 m.appear[0] = m.appear[1];
43 m.appear[1] = tmp;
44 });
45 }
46 }
47 else //other cases
48 moves.push(move);
49 return moves;
50 }
51
52 getPotentialMovesFrom([x,y], computer)
53 {
54 let moves = super.getPotentialMovesFrom([x,y]);
55 // Add switches: respecting chessboard ordering if "computer" is on
56 const color = this.turn;
57 const piece = this.getPiece(x,y);
58 const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
59 const kp = this.kingPos[color];
60 const oppCol = V.GetOppCol(color);
61 for (let step of steps)
62 {
63 let [i,j] = [x+step[0],y+step[1]];
64 if (!!computer && (i<x || (i==x && j<y)))
65 continue; //only switch with superior indices
66 if (V.OnBoard(i,j) && this.board[i][j]!=V.EMPTY
67 && this.getColor(i,j)==color && this.getPiece(i,j)!=piece
68 // No switching under check (theoretically non-king pieces could, but not)
69 && !this.isAttacked(kp, [oppCol]))
70 {
71 let switchMove_s = this.getSwitchMove_s([x,y],[i,j]);
72 if (switchMove_s.length == 1)
73 moves.push(switchMove_s[0]);
74 else //promotion
75 moves = moves.concat(switchMove_s);
76 }
77 }
78 return moves;
79 }
80
81 getAllValidMoves(computer)
82 {
83 const color = this.turn;
84 const oppCol = V.GetOppCol(color);
85 let potentialMoves = [];
86 for (let i=0; i<V.size.x; i++)
87 {
88 for (let j=0; j<V.size.y; j++)
89 {
90 if (this.board[i][j] != V.EMPTY && this.getColor(i,j) == color)
91 {
92 Array.prototype.push.apply(potentialMoves,
93 this.getPotentialMovesFrom([i,j], computer));
94 }
95 }
96 }
97 return this.filterValid(potentialMoves);
98 }
99
100 updateVariables(move)
101 {
102 super.updateVariables(move);
103 if (move.appear.length == 2 && move.vanish.length == 2
104 && move.appear[1].p == V.KING)
105 {
106 // Switch with the king; not castle, and not handled by main class
107 const color = move.vanish[0].c;
108 this.kingPos[color] = [move.appear[1].x, move.appear[1].y];
109 }
110 }
111
112 unupdateVariables(move)
113 {
114 super.unupdateVariables(move);
115 if (move.appear.length == 2 && move.vanish.length == 2
116 && move.appear[1].p == V.KING)
117 {
118 const color = move.vanish[0].c;
119 this.kingPos[color] = [move.appear[0].x, move.appear[0].y];
120 }
121 }
122
123 static get SEARCH_DEPTH() { return 2; } //high branching factor
124
125 getNotation(move)
126 {
127 if (move.appear.length == 1)
128 return super.getNotation(move); //no switch
129 // Switch or castle
130 if (move.appear[0].p == V.KING && move.appear[1].p == V.ROOK)
131 return (move.end.y < move.start.y ? "0-0-0" : "0-0");
132 // Switch:
133 return "S" + V.CoordsToSquare(move.start) + V.CoordsToSquare(move.end);
134 }
135 }