Add Tencubed and Omega variants + some fixes (updateCastleFlags()) + cleaner FEN...
[vchess.git] / client / src / variants / Tencubed.js
1 import { ChessRules } from "@/base_rules";
2 import { ArrayFun } from "@/utils/array";
3 import { shuffle } from "@/utils/alea";
4
5 export class TencubedRules extends ChessRules {
6 static get PawnSpecs() {
7 return Object.assign(
8 {},
9 ChessRules.PawnSpecs,
10 {
11 initShift: { w: 2, b: 2 },
12 promotions: [V.QUEEN, V.MARSHALL, V.ARCHBISHOP]
13 }
14 );
15 }
16
17 static get HasFlags() {
18 return false;
19 }
20
21 getPpath(b) {
22 return (
23 [V.MARSHALL, V.ARCHBISHOP, V.CHAMPION, V.WIZARD].includes(b[1])
24 ? "Tencubed/"
25 : ""
26 ) + b;
27 }
28
29 static get size() {
30 return { x: 10, y: 10 };
31 }
32
33 // Rook + knight:
34 static get MARSHALL() {
35 return "m";
36 }
37
38 // Bishop + knight
39 static get ARCHBISHOP() {
40 return "a";
41 }
42
43 // Dabbabah + alfil + wazir
44 static get CHAMPION() {
45 return "c";
46 }
47
48 // Camel + ferz
49 static get WIZARD() {
50 return "w";
51 }
52
53 static get PIECES() {
54 return (
55 ChessRules.PIECES
56 .concat([V.MARSHALL, V.ARCHBISHOP, V.CHAMPION, V.WIZARD])
57 );
58 }
59
60 static get steps() {
61 return Object.assign(
62 {},
63 ChessRules.steps,
64 {
65 w: [
66 [-3, -1],
67 [-3, 1],
68 [-1, -3],
69 [-1, 3],
70 [1, -3],
71 [1, 3],
72 [3, -1],
73 [3, 1],
74 [-1, -1],
75 [-1, 1],
76 [1, -1],
77 [1, 1]
78 ],
79 c: [
80 [1, 0],
81 [-1, 0],
82 [0, 1],
83 [0, -1],
84 [2, 2],
85 [2, -2],
86 [-2, 2],
87 [-2, -2],
88 [-2, 0],
89 [0, -2],
90 [2, 0],
91 [0, 2]
92 ]
93 }
94 );
95 }
96
97 static GenRandInitFen(randomness) {
98 if (randomness == 0) {
99 return (
100 "2cwamwc2/1rnbqkbnr1/pppppppppp/91/91/" +
101 "91/91/PPPPPPPPPP/1RNBQKBNR1/2CWAMWC2/ " +
102 "w 0 bibi -"
103 );
104 }
105
106 const baseFen = V.ParseFen(ChessRules.GenRandInitFen(randomness));
107 const positionParts = baseFen.position.split("/");
108 const bFen = (
109 "1" + positionParts[0] +
110 "1/pppppppppp/91/91/91/91/PPPPPPPPPP/1" +
111 positionParts[7] + "1"
112 );
113 // Now just obtain randomized new pieces placements:
114 let pieces = { w: new Array(6), b: new Array(6) };
115 for (let c of ["w", "b"]) {
116 if (c == 'b' && randomness == 1) {
117 pieces['b'] = pieces['w'];
118 break;
119 }
120
121 let positions = shuffle(ArrayFun.range(6));
122 const composition = ['w', 'w', 'c', 'c', 'a', 'm'];
123 let rem2 = positions[0] % 2;
124 if (rem2 == positions[1] % 2) {
125 // Fix wizards (on different colors)
126 for (let i=4; i<6; i++) {
127 if (positions[i] % 2 != rem2)
128 [positions[1], positions[i]] = [positions[i], positions[1]];
129 }
130 }
131 rem2 = positions[2] % 2;
132 if (rem2 == positions[3] % 2) {
133 // Fix champions too: [NOTE: positions[4] & [5] should do]
134 for (let i=4; i<6; i++) {
135 if (positions[i] % 2 != rem2)
136 [positions[3], positions[i]] = [positions[i], positions[3]];
137 }
138 }
139 for (let i = 0; i < 9; i++) pieces[c][positions[i]] = composition[i];
140 }
141 return (
142 "2" + pieces["b"].join("") + "2/" +
143 bFen +
144 "/2" + pieces["w"].join("").toUpperCase() + "2" +
145 " w 0 -"
146 );
147 }
148
149 getPotentialMovesFrom([x, y]) {
150 switch (this.getPiece(x, y)) {
151 case V.MARSHALL:
152 return this.getPotentialMarshallMoves([x, y]);
153 case V.ARCHBISHOP:
154 return this.getPotentialArchbishopMoves([x, y]);
155 case V.CHAMPION:
156 return this.getPotentialChampionMoves([x, y]);
157 case V.WIZARD:
158 return this.getPotentialWizardMoves([x, y]);
159 default:
160 return super.getPotentialMovesFrom([x, y]);
161 }
162 }
163
164 getPotentialMarshallMoves(sq) {
165 return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat(
166 this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
167 );
168 }
169
170 getPotentialArchbishopMoves(sq) {
171 return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
172 this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
173 );
174 }
175
176 getPotentialChampionMoves(sq) {
177 return this.getSlideNJumpMoves(sq, V.steps[V.CHAMPION], "oneStep");
178 }
179
180 getPotentialWizardMoves(sq) {
181 return this.getSlideNJumpMoves(sq, V.steps[V.WIZARD], "oneStep");
182 }
183
184 isAttacked(sq, color) {
185 return (
186 super.isAttacked(sq, color) ||
187 this.isAttackedByMarshall(sq, color) ||
188 this.isAttackedByArchbishop(sq, color) ||
189 this.isAttackedByChampion(sq, color) ||
190 this.isAttackedByWizard(sq, color)
191 );
192 }
193
194 isAttackedByMarshall(sq, color) {
195 return (
196 this.isAttackedBySlideNJump(sq, color, V.MARSHALL, V.steps[V.ROOK]) ||
197 this.isAttackedBySlideNJump(
198 sq,
199 color,
200 V.MARSHALL,
201 V.steps[V.KNIGHT],
202 "oneStep"
203 )
204 );
205 }
206
207 isAttackedByArchbishop(sq, color) {
208 return (
209 this.isAttackedBySlideNJump(sq, color, V.CARDINAL, V.steps[V.BISHOP]) ||
210 this.isAttackedBySlideNJump(
211 sq,
212 color,
213 V.CARDINAL,
214 V.steps[V.KNIGHT],
215 "oneStep"
216 )
217 );
218 }
219
220 isAttackedByWizard(sq, color) {
221 return (
222 this.isAttackedBySlideNJump(
223 sq, color, V.WIZARD, V.steps[V.WIZARD], "oneStep")
224 );
225 }
226
227 isAttackedByChampion(sq, color) {
228 return (
229 this.isAttackedBySlideNJump(
230 sq, color, V.CHAMPION, V.steps[V.CHAMPION], "oneStep")
231 );
232 }
233
234 static get SEARCH_DEPTH() {
235 return 2;
236 }
237
238 static get VALUES() {
239 return Object.assign(
240 {},
241 ChessRules.VALUES,
242 { c: 4, w: 3, a: 6, m: 8 }
243 );
244 }
245 };