Several small improvements + integrate options + first working draft of Cwda
[vchess.git] / client / src / variants / Shatranj.js
1 import { ChessRules } from "@/base_rules";
2
3 export class ShatranjRules extends ChessRules {
4
5 static get HasFlags() {
6 return false;
7 }
8
9 static get HasEnpassant() {
10 return false;
11 }
12
13 static get Monochrome() {
14 return true;
15 }
16
17 static get Notoodark() {
18 return true;
19 }
20
21 static get PawnSpecs() {
22 return Object.assign(
23 {},
24 ChessRules.PawnSpecs,
25 {
26 twoSquares: false,
27 promotions: [V.QUEEN]
28 }
29 );
30 }
31
32 getPpath(b) {
33 if (b[1] == 'b') return "Shatranj/" + b;
34 return b;
35 }
36
37 static get ElephantSteps() {
38 return [
39 [-2, -2],
40 [-2, 2],
41 [2, -2],
42 [2, 2]
43 ];
44 }
45
46 static GenRandInitFen(options) {
47 // Remove castle flags and en-passant indication
48 return ChessRules.GenRandInitFen(options).slice(0, -7);
49 }
50
51 getPotentialBishopMoves(sq) {
52 let moves = this.getSlideNJumpMoves(sq, V.ElephantSteps, 1);
53 // Complete with "repositioning moves": like a queen, without capture
54 let repositioningMoves =
55 this.getSlideNJumpMoves(sq, V.steps[V.BISHOP], 1)
56 .filter(m => m.vanish.length == 1);
57 return moves.concat(repositioningMoves);
58 }
59
60 getPotentialQueenMoves(sq) {
61 // Diagonal capturing moves
62 let captures =
63 this.getSlideNJumpMoves(sq, V.steps[V.BISHOP], 1)
64 .filter(m => m.vanish.length == 2);
65 return captures.concat(
66 // Orthogonal non-capturing moves
67 this.getSlideNJumpMoves(sq, V.steps[V.ROOK], 1)
68 .filter(m => m.vanish.length == 1)
69 );
70 }
71
72 isAttackedByBishop(sq, color) {
73 return this.isAttackedBySlideNJump(
74 sq, color, V.BISHOP, V.ElephantSteps, 1);
75 }
76
77 isAttackedByQueen(sq, color) {
78 return this.isAttackedBySlideNJump(
79 sq, color, V.QUEEN, V.steps[V.BISHOP], 1);
80 }
81
82 getCurrentScore() {
83 const color = this.turn;
84 const getScoreLost = () => {
85 // Result if I lose:
86 return color == "w" ? "0-1" : "1-0";
87 };
88 if (!this.atLeastOneMove())
89 // No valid move: I lose (this includes checkmate)
90 return getScoreLost();
91 // Win if the opponent has no pieces left (except king),
92 // and cannot bare king on the next move.
93 let piecesLeft = {
94 // No need to remember all pieces' squares:
95 // variable only used if just one remaining piece.
96 "w": {count: 0, square: null},
97 "b": {count: 0, square: null}
98 };
99 outerLoop: for (let i=0; i<V.size.x; i++) {
100 for (let j=0; j<V.size.y; j++) {
101 if (this.board[i][j] != V.EMPTY && this.getPiece(i,j) != V.KING) {
102 const sqCol = this.getColor(i,j);
103 piecesLeft[sqCol].count++;
104 piecesLeft[sqCol].square = [i,j];
105 }
106 }
107 }
108 if (Object.values(piecesLeft).every(v => v.count > 0))
109 return "*";
110 // No pieces left for some side: if both kings are bare, it's a draw
111 if (Object.values(piecesLeft).every(v => v.count == 0))
112 return "1/2";
113 if (piecesLeft[color].count > 0)
114 // He could have drawn, but didn't take my last piece...
115 return color == "w" ? "1-0" : "0-1";
116 const oppCol = V.GetOppCol(color);
117 if (piecesLeft[oppCol].count >= 2)
118 // 2 enemy units or more: I lose
119 return getScoreLost();
120 // I don't have any piece, my opponent have one: can I take it?
121 if (this.isAttacked(piecesLeft[oppCol].square, color))
122 // Yes! But I still need to take it
123 return "*";
124 // No :(
125 return getScoreLost();
126 }
127
128 static get VALUES() {
129 return {
130 p: 1,
131 r: 5,
132 n: 3,
133 b: 3,
134 q: 3,
135 k: 1000
136 };
137 }
138
139 };