Several small improvements + integrate options + first working draft of Cwda
[vchess.git] / client / src / variants / Zen.js
1 import { ChessRules } from "@/base_rules";
2
3 export class ZenRules extends ChessRules {
4
5 getEpSquare(moveOrSquare) {
6 if (!moveOrSquare) return undefined;
7 if (typeof moveOrSquare === "string") {
8 const square = moveOrSquare;
9 if (square == "-") return undefined;
10 return V.SquareToCoords(square);
11 }
12 const move = moveOrSquare;
13 const s = move.start,
14 e = move.end;
15 if (
16 // Exclude captures (of rooks for example)
17 move.vanish.length == 1 &&
18 s.y == e.y &&
19 Math.abs(s.x - e.x) == 2 &&
20 move.appear[0].p == V.PAWN
21 ) {
22 return {
23 x: (s.x + e.x) / 2,
24 y: s.y
25 };
26 }
27 return undefined;
28 }
29
30 // follow steps from x,y until something is met.
31 // if met piece is opponent and same movement (asA): eat it!
32 findCaptures_aux([x, y], asA) {
33 const color = this.getColor(x, y);
34 let moves = [];
35 const steps =
36 asA != V.PAWN
37 ? asA == V.QUEEN
38 ? V.steps[V.ROOK].concat(V.steps[V.BISHOP])
39 : V.steps[asA]
40 : color == "w"
41 ? [
42 [-1, -1],
43 [-1, 1]
44 ]
45 : [
46 [1, -1],
47 [1, 1]
48 ];
49 const oneStep = [V.KNIGHT,V.PAWN].includes(asA); //we don't capture king
50 const lastRank = color == "w" ? 0 : V.size.x - 1;
51 const promotionPieces = [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN];
52 const oppCol = V.GetOppCol(color);
53 outerLoop: for (let loop = 0; loop < steps.length; loop++) {
54 const step = steps[loop];
55 let i = x + step[0];
56 let j = y + step[1];
57 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
58 if (oneStep) continue outerLoop;
59 i += step[0];
60 j += step[1];
61 }
62 if (
63 V.OnBoard(i, j) &&
64 this.board[i][j] != V.EMPTY &&
65 this.getColor(i, j) == oppCol &&
66 this.getPiece(i, j) == asA
67 ) {
68 // eat!
69 if (this.getPiece(x, y) == V.PAWN && i == lastRank) {
70 // Special case of promotion:
71 promotionPieces.forEach(p => {
72 moves.push(this.getBasicMove([x, y], [i, j], { c: color, p: p }));
73 });
74 }
75 else {
76 // All other cases
77 moves.push(this.getBasicMove([x, y], [i, j]));
78 }
79 }
80 }
81 return moves;
82 }
83
84 // Find possible captures from a square: look in every direction!
85 findCaptures(sq) {
86 let moves = [];
87 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.PAWN));
88 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.ROOK));
89 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.KNIGHT));
90 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.BISHOP));
91 Array.prototype.push.apply(moves, this.findCaptures_aux(sq, V.QUEEN));
92 return moves;
93 }
94
95 canTake() {
96 return false; //captures handled separately
97 }
98
99 getPotentialMovesFrom(sq) {
100 return super.getPotentialMovesFrom(sq).concat(this.findCaptures(sq));
101 }
102
103 getNotation(move) {
104 // Recognize special moves first
105 if (move.appear.length == 2) {
106 // castle
107 if (move.end.y < move.start.y) return "0-0-0";
108 return "0-0";
109 }
110
111 // Translate initial square (because pieces may fly unusually!)
112 const initialSquare = V.CoordsToSquare(move.start);
113
114 // Translate final square
115 const finalSquare = V.CoordsToSquare(move.end);
116
117 let notation = "";
118 const piece = this.getPiece(move.start.x, move.start.y);
119 if (piece == V.PAWN) {
120 // pawn move (TODO: enPassant indication)
121 if (move.vanish.length == 2) {
122 // capture
123 notation = initialSquare + "x" + finalSquare;
124 }
125 else notation = finalSquare;
126 if (piece != move.appear[0].p)
127 //promotion
128 notation += "=" + move.appear[0].p.toUpperCase();
129 }
130 else {
131 // Piece movement
132 notation = piece.toUpperCase();
133 if (move.vanish.length > 1) notation += initialSquare + "x";
134 notation += finalSquare;
135 }
136 return notation;
137 }
138
139 static get VALUES() {
140 return {
141 p: 1,
142 r: 3,
143 n: 2,
144 b: 2,
145 q: 5,
146 k: 1000
147 };
148 }
149
150 };