Add Diamond Chess
[vchess.git] / client / src / variants / Diamond.js
1 import { ChessRules } from "@/base_rules";
2 import { ArrayFun } from "@/utils/array";
3 import { shuffle } from "@/utils/alea";
4
5 export class DiamondRules extends ChessRules {
6 static get HasFlags() {
7 return false;
8 }
9
10 static get HasEnpassant() {
11 return false;
12 }
13
14 static GenRandInitFen(randomness) {
15 if (randomness == 0)
16 return "krbp4/rqnp4/nbpp4/pppp4/4PPPP/4PPBN/4PNQR/4PBRK w 0";
17 let pieces = { w: new Array(8), b: new Array(8) };
18 for (let c of ["w", "b"]) {
19 if (c == 'b' && randomness == 1) {
20 pieces['b'] = pieces['w'];
21 break;
22 }
23 // Get random squares for every piece, totally freely
24 let positions = shuffle(ArrayFun.range(8));
25 const composition = ['b', 'b', 'r', 'r', 'n', 'n', 'k', 'q'];
26 const rem2 = positions[0] % 2;
27 if (rem2 == positions[1] % 2) {
28 // Fix bishops (on different colors)
29 for (let i=2; i<8; i++) {
30 if (positions[i] % 2 != rem2)
31 [positions[1], positions[i]] = [positions[i], positions[1]];
32 }
33 }
34 for (let i = 0; i < 8; i++) pieces[c][positions[i]] = composition[i];
35 }
36 return (
37 pieces["b"].slice(0, 3).join("") + "p4/" +
38 pieces["b"].slice(3, 6).join("") + "p4/" +
39 pieces["b"].slice(6, 8).join("") + "pp4/" +
40 "pppp4/4PPPP/" +
41 "4PP" + pieces["w"].slice(6, 8).reverse().join("").toUpperCase() + "/" +
42 "4P" + pieces["w"].slice(3, 6).reverse().join("").toUpperCase() + "/" +
43 "4P" + pieces["w"].slice(0, 3).reverse().join("").toUpperCase() +
44 " w 0"
45 );
46 }
47
48 // Special pawns movements
49 getPotentialPawnMoves([x, y]) {
50 const color = this.turn;
51 let moves = [];
52 const [sizeX, sizeY] = [V.size.x, V.size.y];
53 const shift = (color == "w" ? -1 : 1);
54 const lastRank = (color == "w" ? 0 : 7);
55
56 // One square forward (diagonally along h1-a8)
57 if (this.board[x + shift][y + shift] == V.EMPTY) {
58 const finalPieces =
59 [x + shift, y + shift].includes(lastRank)
60 ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]
61 : [V.PAWN];
62 for (let piece of finalPieces) {
63 moves.push(
64 this.getBasicMove(
65 [x, y], [x + shift, y + shift], { c: color, p: piece })
66 );
67 }
68 }
69 // Capture
70 for (let pShift of [[0, shift], [shift, 0]]) {
71 if (
72 this.board[x + pShift[0]][y + pShift[1]] != V.EMPTY &&
73 this.canTake([x, y], [x + pShift[0], y + pShift[1]])
74 ) {
75 const finalPieces =
76 [x + pShift[0], y + pShift[1]].includes(lastRank)
77 ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]
78 : [V.PAWN];
79 for (let piece of finalPieces) {
80 moves.push(
81 this.getBasicMove(
82 [x, y],
83 [x + pShift[0], y + pShift[1]],
84 {
85 c: color,
86 p: piece
87 }
88 )
89 );
90 }
91 }
92 }
93
94 return moves;
95 }
96
97 isAttackedByPawn([x, y], color) {
98 let pawnShift = (color == "w" ? 1 : -1);
99 return (
100 (
101 x + pawnShift >= 0 && x + pawnShift < V.size.x &&
102 this.getPiece(x + pawnShift, y) == V.PAWN &&
103 this.getColor(x + pawnShift, y) == color
104 )
105 ||
106 (
107 y + pawnShift >= 0 && y + pawnShift < V.size.y &&
108 this.getPiece(x, y + pawnShift) == V.PAWN &&
109 this.getColor(x, y + pawnShift) == color
110 )
111 );
112 }
113
114 static get SEARCH_DEPTH() {
115 return 2;
116 }
117
118 getNotation(move) {
119 const piece = this.getPiece(move.start.x, move.start.y);
120 if (piece == V.PAWN) {
121 // Pawn move
122 const finalSquare = V.CoordsToSquare(move.end);
123 let notation = "";
124 if (move.vanish.length == 2)
125 // Capture
126 notation = "Px" + finalSquare;
127 else {
128 // No capture: indicate the initial square for potential ambiguity
129 const startSquare = V.CoordsToSquare(move.start);
130 notation = startSquare + finalSquare;
131 }
132 if (move.appear[0].p != V.PAWN)
133 // Promotion
134 notation += "=" + move.appear[0].p.toUpperCase();
135 return notation;
136 }
137 return super.getNotation(move); //all other pieces are orthodox
138 }
139 };