Draft Ball variant + some fixes, enhancements and code cleaning
[vchess.git] / client / src / variants / Arena.js
1 import { ChessRules } from "@/base_rules";
2
3 export class ArenaRules extends ChessRules {
4 static get HasFlags() {
5 return false;
6 }
7
8 static get PawnSpecs() {
9 return Object.assign(
10 {},
11 ChessRules.PawnSpecs,
12 { captureBackward: true }
13 );
14 }
15
16 static IsGoodPosition(position) {
17 if (position.length == 0) return false;
18 const rows = position.split("/");
19 if (rows.length != V.size.x) return false;
20 // At most and at least one king or queen per color
21 let royals = { "k": 0, "K": 0, "q": 0, "Q": 0 };
22 for (let row of rows) {
23 let sumElts = 0;
24 for (let i = 0; i < row.length; i++) {
25 if (['K','k','Q','q'].includes(row[i])) royals[row[i]]++;
26 if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
27 else {
28 const num = parseInt(row[i]);
29 if (isNaN(num)) return false;
30 sumElts += num;
31 }
32 }
33 if (sumElts != V.size.y) return false;
34 }
35 if (
36 Object.values(royals).some(v => v >= 2) ||
37 royals['K'] + royals['Q'] == 0 ||
38 royals['k'] + royals['q'] == 0
39 ) {
40 return false;
41 }
42 return true;
43 }
44
45 scanKings() {}
46
47 static GenRandInitFen(randomness) {
48 return ChessRules.GenRandInitFen(randomness).slice(0, -6) + "-";
49 }
50
51 static InArena(x) {
52 return Math.abs(3.5 - x) <= 1.5;
53 }
54
55 getPotentialMovesFrom([x, y]) {
56 const moves = super.getPotentialMovesFrom([x, y]);
57 // Eliminate moves which neither enter the arena or capture something
58 return moves.filter(m => {
59 const startInArena = V.InArena(m.start.x);
60 const endInArena = V.InArena(m.end.x);
61 return (
62 (startInArena && endInArena && m.vanish.length == 2) ||
63 (!startInArena && endInArena)
64 );
65 });
66
67 return moves;
68 }
69
70 getPotentialQueenMoves(sq) {
71 return this.getSlideNJumpMoves(
72 sq,
73 V.steps[V.ROOK].concat(V.steps[V.BISHOP])
74 ).filter(m => {
75 // Filter out moves longer than 3 squares
76 return Math.max(
77 Math.abs(m.end.x - m.start.x),
78 Math.abs(m.end.y - m.start.y)) <= 3;
79 });
80 }
81
82 getPotentialKingMoves(sq) {
83 return this.getSlideNJumpMoves(
84 sq,
85 V.steps[V.ROOK].concat(V.steps[V.BISHOP])
86 ).filter(m => {
87 // Filter out moves longer than 3 squares
88 return Math.max(
89 Math.abs(m.end.x - m.start.x),
90 Math.abs(m.end.y - m.start.y)) <= 3;
91 });
92 }
93
94 getCheckSquares() {
95 return [];
96 }
97
98 filterValid(moves) {
99 // No check conditions
100 return moves;
101 }
102
103 getCurrentScore() {
104 const color = this.turn;
105 if (!this.atLeastOneMove())
106 // I cannot move anymore
107 return color == "w" ? "0-1" : "1-0";
108 // Win if the opponent has no more pieces left (in the Arena),
109 // (and/)or if he lost both his dukes.
110 let someUnitRemain = false;
111 let atLeastOneDuke = false;
112 let somethingInArena = false;
113 outerLoop: for (let i=0; i<V.size.x; i++) {
114 for (let j=0; j<V.size.y; j++) {
115 if (this.getColor(i,j) == color) {
116 someUnitRemain = true;
117 if (this.movesCount >= 2 && V.InArena(i)) {
118 somethingInArena = true;
119 if (atLeastOneDuke)
120 break outerLoop;
121 }
122 if ([V.QUEEN,V.KING].includes(this.getPiece(i,j))) {
123 atLeastOneDuke = true;
124 if (this.movesCount < 2 || somethingInArena)
125 break outerLoop;
126 }
127 }
128 }
129 }
130 if (
131 !someUnitRemain ||
132 !atLeastOneDuke ||
133 (this.movesCount >= 2 && !somethingInArena)
134 ) {
135 return color == "w" ? "0-1" : "1-0";
136 }
137 return "*";
138 }
139
140 static get SEARCH_DEPTH() {
141 return 4;
142 }
143 };