Fix parseInt() usage, rename Doubleorda --> Ordamirror, implement Clorange variant
[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], 10);
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 postPlay() {} //no kingPos no castleFlags
104 postUndo() {}
105
106 getCurrentScore() {
107 const color = this.turn;
108 if (!this.atLeastOneMove())
109 // I cannot move anymore
110 return color == "w" ? "0-1" : "1-0";
111 // Win if the opponent has no more pieces left (in the Arena),
112 // (and/)or if he lost both his dukes.
113 let someUnitRemain = false;
114 let atLeastOneDuke = false;
115 let somethingInArena = false;
116 outerLoop: for (let i=0; i<V.size.x; i++) {
117 for (let j=0; j<V.size.y; j++) {
118 if (this.getColor(i,j) == color) {
119 someUnitRemain = true;
120 if (this.movesCount >= 2 && V.InArena(i)) {
121 somethingInArena = true;
122 if (atLeastOneDuke)
123 break outerLoop;
124 }
125 if ([V.QUEEN,V.KING].includes(this.getPiece(i,j))) {
126 atLeastOneDuke = true;
127 if (this.movesCount < 2 || somethingInArena)
128 break outerLoop;
129 }
130 }
131 }
132 }
133 if (
134 !someUnitRemain ||
135 !atLeastOneDuke ||
136 (this.movesCount >= 2 && !somethingInArena)
137 ) {
138 return color == "w" ? "0-1" : "1-0";
139 }
140 return "*";
141 }
142
143 static get SEARCH_DEPTH() {
144 return 4;
145 }
146 };