Several small improvements + integrate options + first working draft of Cwda
[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
7 static get PawnSpecs() {
8 return Object.assign(
9 {},
10 ChessRules.PawnSpecs,
11 {
12 initShift: { w: 2, b: 2 },
13 promotions: [V.QUEEN, V.MARSHALL, V.ARCHBISHOP]
14 }
15 );
16 }
17
18 static get HasFlags() {
19 return false;
20 }
21
22 getPpath(b) {
23 return (
24 [V.MARSHALL, V.ARCHBISHOP, V.CHAMPION, V.WIZARD].includes(b[1])
25 ? "Tencubed/"
26 : ""
27 ) + b;
28 }
29
30 static get size() {
31 return { x: 10, y: 10 };
32 }
33
34 // Rook + knight:
35 static get MARSHALL() {
36 return "m";
37 }
38
39 // Bishop + knight
40 static get ARCHBISHOP() {
41 return "a";
42 }
43
44 // Dabbabah + alfil + wazir
45 static get CHAMPION() {
46 return "c";
47 }
48
49 // Camel + ferz
50 static get WIZARD() {
51 return "w";
52 }
53
54 static get PIECES() {
55 return (
56 ChessRules.PIECES
57 .concat([V.MARSHALL, V.ARCHBISHOP, V.CHAMPION, V.WIZARD])
58 );
59 }
60
61 static get steps() {
62 return Object.assign(
63 {
64 w: [
65 [-3, -1],
66 [-3, 1],
67 [-1, -3],
68 [-1, 3],
69 [1, -3],
70 [1, 3],
71 [3, -1],
72 [3, 1],
73 [-1, -1],
74 [-1, 1],
75 [1, -1],
76 [1, 1]
77 ],
78 c: [
79 [1, 0],
80 [-1, 0],
81 [0, 1],
82 [0, -1],
83 [2, 2],
84 [2, -2],
85 [-2, 2],
86 [-2, -2],
87 [-2, 0],
88 [0, -2],
89 [2, 0],
90 [0, 2]
91 ]
92 },
93 ChessRules.steps,
94 );
95 }
96
97 static GenRandInitFen(options) {
98 if (options.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(options));
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], 1)
167 );
168 }
169
170 getPotentialArchbishopMoves(sq) {
171 return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
172 this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], 1)
173 );
174 }
175
176 getPotentialChampionMoves(sq) {
177 return this.getSlideNJumpMoves(sq, V.steps[V.CHAMPION], 1);
178 }
179
180 getPotentialWizardMoves(sq) {
181 return this.getSlideNJumpMoves(sq, V.steps[V.WIZARD], 1);
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(sq, color, V.MARSHALL, V.steps[V.KNIGHT], 1)
198 );
199 }
200
201 isAttackedByArchbishop(sq, color) {
202 return (
203 this.isAttackedBySlideNJump(
204 sq, color, V.ARCHBISHOP, V.steps[V.BISHOP])
205 ||
206 this.isAttackedBySlideNJump(
207 sq, color, V.ARCHBISHOP, V.steps[V.KNIGHT], 1)
208 );
209 }
210
211 isAttackedByWizard(sq, color) {
212 return this.isAttackedBySlideNJump(
213 sq, color, V.WIZARD, V.steps[V.WIZARD], 1);
214 }
215
216 isAttackedByChampion(sq, color) {
217 return this.isAttackedBySlideNJump(
218 sq, color, V.CHAMPION, V.steps[V.CHAMPION], 1);
219 }
220
221 static get SEARCH_DEPTH() {
222 return 2;
223 }
224
225 static get VALUES() {
226 return Object.assign(
227 {
228 c: 4,
229 w: 3,
230 a: 6,
231 m: 8
232 },
233 ChessRules.VALUES
234 );
235 }
236
237 };