Better Ball rules. Buggish but almost OK Synchrone variant
[vchess.git] / client / src / variants / Twokings.js
1 import { ChessRules } from "@/base_rules";
2 import { CoregalRules } from "@/variants/Coregal";
3
4 export class TwokingsRules extends CoregalRules {
5 static get PawnSpecs() {
6 return Object.assign(
7 {},
8 ChessRules.PawnSpecs,
9 { promotions: ChessRules.PawnSpecs.promotions.concat([V.KING]) }
10 );
11 }
12
13 static IsGoodPosition(position) {
14 if (position.length == 0) return false;
15 const rows = position.split("/");
16 if (rows.length != V.size.x) return false;
17 let kings = { "w": 0, "b": 0 };
18 for (let row of rows) {
19 let sumElts = 0;
20 for (let i = 0; i < row.length; i++) {
21 if (['K','k'].includes(row[i])) kings[row[i]]++;
22 if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
23 else {
24 const num = parseInt(row[i]);
25 if (isNaN(num)) return false;
26 sumElts += num;
27 }
28 }
29 if (sumElts != V.size.y) return false;
30 }
31 // Two kings (at least) per side should be present:
32 if (Object.values(kings).some(v => v < 2)) return false;
33 return true;
34 }
35
36 // Not scanning king positions. In this variant, scan the board everytime.
37 scanKings() {}
38
39 getCheckSquares(color) {
40 let squares = [];
41 const oppCol = V.GetOppCol(color);
42 for (let i=0; i<V.size.x; i++) {
43 for (let j=0; j<V.size.y; j++) {
44 if (
45 this.getColor(i, j) == color &&
46 this.getPiece(i, j) == V.KING &&
47 this.isAttacked([i, j], oppCol)
48 ) {
49 squares.push([i, j]);
50 }
51 }
52 }
53 return squares;
54 }
55
56 static GenRandInitFen(randomness) {
57 if (randomness == 0)
58 return "rnqkkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNQKKBNR w 0 adehadeh -";
59
60 const replaceBishop = (fen, first, ch1, ch2) => {
61 // Remove and re-add final part:
62 const suffix = fen.substr(-15);
63 fen = fen.slice(0, -15);
64 if (first) fen = fen.replace(ch1, ch2);
65 else {
66 fen =
67 fen.split("").reverse().join("")
68 .replace(ch1, ch2)
69 .split("").reverse().join("")
70 }
71 return fen + suffix;
72 };
73
74 const sameIndexReplace = (fen) => {
75 const first = (Math.random() < 0.5);
76 return replaceBishop(
77 replaceBishop(fen, first, 'B', 'Q'),
78 first,
79 'b',
80 'q'
81 );
82 };
83
84 const fen =
85 CoregalRules.GenRandInitFen(randomness)
86 .replace("q", "k").replace("Q", "K");
87 // Now replace a bishop by the queen,
88 // so that bishops are of different colors:
89 if (randomness == 1) return sameIndexReplace(fen);
90 const wOdd = fen.indexOf('B') % 2;
91 const bOdd = fen.indexOf('b') % 2;
92 // Since there are 7 slashes, different oddities means symmetric
93 if (wOdd != bOdd) return sameIndexReplace(fen);
94 const wFirst = (Math.random() < 0.5);
95 return replaceBishop(
96 replaceBishop(fen, wFirst, 'B', 'Q'),
97 !wFirst,
98 'b',
99 'q'
100 );
101 }
102
103 underCheck(color) {
104 const oppCol = V.GetOppCol(color);
105 for (let i=0; i<V.size.x; i++) {
106 for (let j=0; j<V.size.y; j++) {
107 if (
108 this.getColor(i, j) == color &&
109 this.getPiece(i, j) == V.KING &&
110 this.isAttacked([i, j], oppCol)
111 ) {
112 return true;
113 }
114 }
115 }
116 return false;
117 }
118
119 postPlay(move) {
120 const piece = move.vanish[0].p;
121 super.updateCastleFlags(move, piece, "twoKings");
122 }
123
124 postUndo() {}
125 };