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