Add an entry to the FAQ
[vchess.git] / client / src / variants / Perfect.js
CommitLineData
a6836242
BA
1import { ChessRules } from "@/base_rules";
2import { ArrayFun } from "@/utils/array";
3import { randInt } from "@/utils/alea";
4
5export class PerfectRules extends ChessRules {
7e8a7ea1 6
a6836242
BA
7 static get PawnSpecs() {
8 return Object.assign(
9 {},
10 ChessRules.PawnSpecs,
11 {
12 promotions:
13 ChessRules.PawnSpecs.promotions
14 .concat([V.AMAZON, V.EMPRESS, V.PRINCESS])
15 }
16 );
17 }
18
19 getPpath(b) {
20 return (
21 [V.AMAZON, V.EMPRESS, V.PRINCESS].includes(b[1])
22 ? "Perfect/"
23 : ""
24 ) + b;
25 }
26
27 // Queen + knight
28 static get AMAZON() {
29 return "a";
30 }
31
32 // Rook + knight
33 static get EMPRESS() {
34 return "e";
35 }
36
37 // Bishop + knight
38 static get PRINCESS() {
39 return "s";
40 }
41
42 static get PIECES() {
43 return ChessRules.PIECES.concat([V.AMAZON, V.EMPRESS, V.PRINCESS]);
44 }
45
46 getPotentialMovesFrom([x, y]) {
47 switch (this.getPiece(x, y)) {
48 case V.AMAZON:
49 return this.getPotentialAmazonMoves([x, y]);
50 case V.EMPRESS:
51 return this.getPotentialEmpressMoves([x, y]);
52 case V.PRINCESS:
53 return this.getPotentialPrincessMoves([x, y]);
54 default:
55 return super.getPotentialMovesFrom([x, y]);
56 }
57 }
58
59 getPotentialAmazonMoves(sq) {
60 return super.getPotentialQueenMoves(sq).concat(
61 this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
62 );
63 }
64
65 getPotentialEmpressMoves(sq) {
66 return this.getSlideNJumpMoves(sq, V.steps[V.ROOK]).concat(
67 this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
68 );
69 }
70
71 getPotentialPrincessMoves(sq) {
72 return this.getSlideNJumpMoves(sq, V.steps[V.BISHOP]).concat(
73 this.getSlideNJumpMoves(sq, V.steps[V.KNIGHT], "oneStep")
74 );
75 }
76
77 isAttacked(sq, color) {
78 return (
79 super.isAttacked(sq, color) ||
80 this.isAttackedByAmazon(sq, color) ||
81 this.isAttackedByEmpress(sq, color) ||
82 this.isAttackedByPrincess(sq, color)
83 );
84 }
85
86 isAttackedByAmazon(sq, color) {
87 return (
61d1baa9
BA
88 this.isAttackedBySlideNJump(sq, color, V.AMAZON, V.steps[V.BISHOP]) ||
89 this.isAttackedBySlideNJump(sq, color, V.AMAZON, V.steps[V.ROOK]) ||
a6836242
BA
90 this.isAttackedBySlideNJump(
91 sq,
92 color,
61d1baa9 93 V.AMAZON,
a6836242
BA
94 V.steps[V.KNIGHT],
95 "oneStep"
96 )
97 );
98 }
99
100 isAttackedByEmpress(sq, color) {
101 return (
61d1baa9 102 this.isAttackedBySlideNJump(sq, color, V.EMPRESS, V.steps[V.ROOK]) ||
a6836242
BA
103 this.isAttackedBySlideNJump(
104 sq,
105 color,
61d1baa9 106 V.EMPRESS,
a6836242
BA
107 V.steps[V.KNIGHT],
108 "oneStep"
109 )
110 );
111 }
112
113 isAttackedByPrincess(sq, color) {
114 return (
61d1baa9 115 this.isAttackedBySlideNJump(sq, color, V.PRINCESS, V.steps[V.BISHOP]) ||
a6836242
BA
116 this.isAttackedBySlideNJump(
117 sq,
118 color,
61d1baa9 119 V.PRINCESS,
a6836242
BA
120 V.steps[V.KNIGHT],
121 "oneStep"
122 )
123 );
124 }
125
126 static get VALUES() {
127 return Object.assign(
128 { a: 12, e: 7, s: 5 }, //experimental
129 ChessRules.VALUES
130 );
131 }
132
133 static get SEARCH_DEPTH() {
134 return 2;
135 }
136
137 static GenRandInitFen(randomness) {
138 if (randomness == 0)
139 return "esqakbnr/pppppppp/8/8/8/8/PPPPPPPP/ESQAKBNR w 0 ahah -";
140
141 let pieces = { w: new Array(8), b: new Array(8) };
142 let flags = "";
143 let whiteBishopPos = -1;
144 for (let c of ["w", "b"]) {
145 if (c == 'b' && randomness == 1) {
146 pieces['b'] = pieces['w'];
147 flags += flags;
148 break;
149 }
150
151 let positions = ArrayFun.range(8);
152
153 // Get random squares for bishop: if black, pick a different color
154 // than where the white one stands.
155 let randIndex =
156 c == 'w'
157 ? randInt(8)
158 : 2 * randInt(4) + (1 - whiteBishopPos % 2);
159 if (c == 'w') whiteBishopPos = randIndex;
160 const bishopPos = positions[randIndex];
161 positions.splice(randIndex, 1);
162
163 randIndex = randInt(7);
164 const knightPos = positions[randIndex];
165 positions.splice(randIndex, 1);
166
167 randIndex = randInt(6);
168 const queenPos = positions[randIndex];
169 positions.splice(randIndex, 1);
170
171 randIndex = randInt(5);
172 const amazonPos = positions[randIndex];
173 positions.splice(randIndex, 1);
174
175 randIndex = randInt(4);
176 const princessPos = positions[randIndex];
177 positions.splice(randIndex, 1);
178
179 // Rook, empress and king positions are now almost fixed,
180 // only the ordering rook->empress or empress->rook must be decided.
181 let rookPos = positions[0];
182 let empressPos = positions[2];
183 const kingPos = positions[1];
184 flags += V.CoordToColumn(rookPos) + V.CoordToColumn(empressPos);
185 if (Math.random() < 0.5) [rookPos, empressPos] = [empressPos, rookPos];
186
187 pieces[c][rookPos] = "r";
188 pieces[c][knightPos] = "n";
189 pieces[c][bishopPos] = "b";
190 pieces[c][queenPos] = "q";
191 pieces[c][kingPos] = "k";
192 pieces[c][amazonPos] = "a";
193 pieces[c][princessPos] = "s";
194 pieces[c][empressPos] = "e";
195 }
196 // Add turn + flags + enpassant
197 return (
198 pieces["b"].join("") +
199 "/pppppppp/8/8/8/8/PPPPPPPP/" +
200 pieces["w"].join("").toUpperCase() +
201 " w 0 " + flags + " -"
202 );
203 }
7e8a7ea1 204
a6836242 205};