Some fixes. Screen variant computer play is still broken, seemingly
[vchess.git] / client / src / variants / Alapo.js
CommitLineData
0f7762c1
BA
1import { ChessRules } from "@/base_rules";
2
3export class AlapoRules extends ChessRules {
4
5 static get HasFlags() {
6 return false;
7 }
8
9 static get HasEnpassant() {
10 return false;
11 }
12
13 static get Lines() {
14 return [
15 [[1, 0], [1, 6]],
16 [[5, 0], [5, 6]]
17 ];
18 }
19
20 static get PIECES() {
21 return [V.ROOK, V.BISHOP, V.QUEEN, V.ROOK_S, V.BISHOP_S, V.QUEEN_S];
22 }
23
24 static get ROOK_S() {
25 return "t";
26 }
27 static get BISHOP_S() {
28 return "c";
29 }
30 static get QUEEN_S() {
31 return "s";
32 }
33
34 getPotentialMinirookMoves(sq) {
35 return super.getSlideNJumpMoves(sq, V.steps[V.ROOK], "oneStep");
36 }
37 getPotentialMinibishopMoves(sq) {
38 return super.getSlideNJumpMoves(sq, V.steps[V.BISHOP], "oneStep");
39 }
40 getPotentialMiniqueenMoves(sq) {
41 return (
42 super.getSlideNJumpMoves(
43 sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep")
44 );
45 }
46
47 getPotentialMovesFrom(sq) {
48 switch (this.getPiece(sq[0], sq[1])) {
49 case V.ROOK: return super.getPotentialRookMoves(sq);
50 case V.BISHOP: return super.getPotentialBishopMoves(sq);
51 case V.QUEEN: return super.getPotentialQueenMoves(sq);
52 case V.ROOK_S: return this.getPotentialMinirookMoves(sq);
53 case V.BISHOP_S: return this.getPotentialMinibishopMoves(sq);
54 case V.QUEEN_S: return this.getPotentialMiniqueenMoves(sq);
55 }
56 return [];
57 }
58
59 static get size() {
60 return { x: 6, y: 6 };
61 }
62
63 getPpath(b, color, score, orientation) {
64 // 'i' for "inversed":
65 const suffix = (b[0] == orientation ? "" : "i");
66 return "Alapo/" + b + suffix;
67 }
68
69 static GenRandInitFen(randomness) {
70 if (randomness == 0)
71 return "rbqqbr/tcssct/6/6/TCSSCT/RBQQBR w 0";
72
73 const piece2pawn = {
74 r: 't',
75 q: 's',
76 b: 'c'
77 };
78
79 let pieces = { w: new Array(6), b: new Array(6) };
80 // Shuffle pieces on first (and last rank if randomness == 2)
81 for (let c of ["w", "b"]) {
82 if (c == 'b' && randomness == 1) {
83 pieces['b'] = pieces['w'];
84 break;
85 }
86
87 let positions = ArrayFun.range(6);
88
89 // Get random squares for bishops
90 let randIndex = 2 * randInt(3);
91 const bishop1Pos = positions[randIndex];
92 let randIndex_tmp = 2 * randInt(3) + 1;
93 const bishop2Pos = positions[randIndex_tmp];
94 positions.splice(Math.max(randIndex, randIndex_tmp), 1);
95 positions.splice(Math.min(randIndex, randIndex_tmp), 1);
96
97 // Get random square for queens
98 randIndex = randInt(4);
99 const queen1Pos = positions[randIndex];
100 positions.splice(randIndex, 1);
101 randIndex = randInt(3);
102 const queen2Pos = positions[randIndex];
103 positions.splice(randIndex, 1);
104
105 // Rooks positions are now fixed,
106 const rook1Pos = positions[0];
107 const rook2Pos = positions[1];
108
109 pieces[c][rook1Pos] = "r";
110 pieces[c][bishop1Pos] = "b";
111 pieces[c][queen1Pos] = "q";
112 pieces[c][queen2Pos] = "q";
113 pieces[c][bishop2Pos] = "b";
114 pieces[c][rook2Pos] = "r";
115 }
116 return (
117 pieces["b"].join("") + "/" +
118 pieces["b"].map(p => piece2pawn[p]).join() +
119 "/8/8/8/8/" +
120 pieces["w"].map(p => piece2pawn[p].toUpperCase()).join() + "/" +
121 pieces["w"].join("").toUpperCase() +
122 " w 0"
123 );
124 }
125
126 static IsGoodPosition(position) {
127 if (position.length == 0) return false;
128 const rows = position.split("/");
129 if (rows.length != V.size.x) return false;
130 // Just check that at least one piece of each color is there:
131 let pieces = { "w": 0, "b": 0 };
132 for (let row of rows) {
133 let sumElts = 0;
134 for (let i = 0; i < row.length; i++) {
135 const lowerRi = row[i].toLowerCase();
136 if (V.PIECES.includes(lowerRi)) {
137 pieces[row[i] == lowerRi ? "b" : "w"]++;
138 sumElts++;
139 }
140 else {
141 const num = parseInt(row[i], 10);
142 if (isNaN(num)) return false;
143 sumElts += num;
144 }
145 }
146 if (sumElts != V.size.y) return false;
147 }
148 if (Object.values(pieces).some(v => v == 0)) return false;
149 return true;
150 }
151
152 // Find possible captures by opponent on [x, y]
153 findCaptures([x, y]) {
154 const color = this.getColor(x, y);
155 let moves = [];
156 const steps = V.steps[V.ROOK].concat(V.steps[V.BISHOP]);
157 const oppCol = V.GetOppCol(color);
158 for (let loop = 0; loop < steps.length; loop++) {
159 const step = steps[loop];
160 let i = x + step[0];
161 let j = y + step[1];
162 let stepsAfter = 1;
163 while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
164 i += step[0];
165 j += step[1];
166 stepsAfter++;
167 }
168 if (
169 V.OnBoard(i, j) &&
170 this.board[i][j] != V.EMPTY &&
171 this.getColor(i, j) == oppCol
172 ) {
173 const oppPiece = this.getPiece(i, j);
174 if (
175 (
176 stepsAfter >= 2 &&
177 [V.ROOK_S, V.BISHOP_S, V.QUEEN_S].includes(oppPiece)
178 )
179 ||
180 (
181 [V.BISHOP, V.BISHOP_S].includes(oppPiece) &&
182 step.some(e => e == 0)
183 )
184 ||
185 (
186 [V.ROOK, V.ROOK_S].includes(oppPiece) &&
187 step.every(e => e != 0)
188 )
189 ) {
190 continue;
191 }
192 return true;
193 }
194 }
195 return false;
196 }
197
198 postPlay() {}
199 postUndo() {}
200
201 getCheckSquares() {
202 return [];
203 }
204 filterValid(moves) {
205 return moves;
206 }
207
208 getCurrentScore() {
209 // Try both colors (to detect potential suicides)
210 for (let c of ['w', 'b']) {
211 const oppCol = V.GetOppCol(c);
212 const goal = (c == 'w' ? 0 : 5);
213 if (
214 this.board[goal].some(
215 (b,j) => b[0] == c && !this.findCaptures([goal, j])
216 )
217 ) {
218 return c == 'w' ? "1-0" : "0-1";
219 }
220 }
221 return super.getCurrentScore();
222 }
223
ded43c88
BA
224 static get VALUES() {
225 return {
226 r: 5,
227 b: 3,
228 q: 9,
229 t: 3,
230 c: 2,
231 s: 5
232 };
233 }
234
0f7762c1 235};