Several small improvements + integrate options + first working draft of Cwda
[vchess.git] / client / src / variants / Align4.js
1 import { ChessRules, Move, PiPo } from "@/base_rules";
2
3 export class Align4Rules extends ChessRules {
4
5 static get Options() {
6 return {
7 check: [
8 {
9 label: "Random",
10 defaut: false,
11 variable: "random"
12 }
13 ]
14 };
15 }
16
17 static GenRandInitFen(options) {
18 const baseFen = ChessRules.GenRandInitFen(
19 { randomness: (options.random ? 1 : 0) });
20 return "4k3/8" + baseFen.substring(17, 50) + " -";
21 }
22
23 getReservePpath() {
24 return "bp";
25 }
26
27 static get RESERVE_PIECES() {
28 return [V.PAWN]; //only black pawns
29 }
30
31 getColor(i, j) {
32 if (i >= V.size.x) return "b";
33 return this.board[i][j].charAt(0);
34 }
35
36 getPiece(i, j) {
37 if (i >= V.size.x) return V.PAWN;
38 return this.board[i][j].charAt(1);
39 }
40
41 static IsGoodFlags(flags) {
42 // Only white can castle
43 return !!flags.match(/^[a-z]{2,2}$/);
44 }
45
46 getFlagsFen() {
47 return this.castleFlags['w'].map(V.CoordToColumn).join("");
48 }
49
50 setFlags(fenflags) {
51 this.castleFlags = { 'w': [-1, -1] };
52 for (let i = 0; i < 2; i++)
53 this.castleFlags['w'][i] = V.ColumnToCoord(fenflags.charAt(i));
54 }
55
56 setOtherVariables(fen) {
57 super.setOtherVariables(fen);
58 this.reserve = { b: { [V.PAWN]: 1 } };
59 }
60
61 getReserveMoves() {
62 if (this.turn != 'b') return [];
63 let moves = [];
64 for (let i = 1; i <= 6; i++) {
65 for (let j = 0; j < V.size.y; j++) {
66 if (this.board[i][j] == V.EMPTY) {
67 let mv = new Move({
68 appear: [
69 new PiPo({
70 x: i,
71 y: j,
72 c: 'b',
73 p: 'p'
74 })
75 ],
76 vanish: [],
77 start: { x: 9, y: 0 },
78 end: { x: i, y: j }
79 });
80 moves.push(mv);
81 }
82 }
83 }
84 return moves;
85 }
86
87 getPotentialMovesFrom(sq) {
88 if (sq[0] >= V.size.x) return this.getReserveMoves();
89 return super.getPotentialMovesFrom(sq);
90 }
91
92 getPotentialKingMoves([x, y]) {
93 if (this.getColor(x, y) == 'w') return super.getPotentialKingMoves([x, y]);
94 // Black doesn't castle:
95 return super.getSlideNJumpMoves(
96 [x, y], V.steps[V.ROOK].concat(V.steps[V.BISHOP]), 1);
97 }
98
99 getAllValidMoves() {
100 return (
101 super.getAllValidMoves().concat(
102 super.filterValid(this.getReserveMoves()))
103 );
104 }
105
106 atLeastOneMove() {
107 if (super.atLeastOneMove()) return true;
108 // Search one reserve move
109 if (this.filterValid(this.getReserveMoves()).length > 0) return true;
110 return false;
111 }
112
113 updateCastleFlags(move, piece) {
114 // Only white can castle:
115 const firstRank = 7;
116 if (piece == V.KING && move.appear[0].c == 'w')
117 this.castleFlags['w'] = [8, 8];
118 else if (
119 move.start.x == firstRank &&
120 this.castleFlags['w'].includes(move.start.y)
121 ) {
122 const flagIdx = (move.start.y == this.castleFlags['w'][0] ? 0 : 1);
123 this.castleFlags['w'][flagIdx] = 8;
124 }
125 else if (
126 move.end.x == firstRank &&
127 this.castleFlags['w'].includes(move.end.y)
128 ) {
129 const flagIdx = (move.end.y == this.castleFlags['w'][0] ? 0 : 1);
130 this.castleFlags['w'][flagIdx] = 8;
131 }
132 }
133
134 getCurrentScore() {
135 const score = super.getCurrentScore();
136 if (score != "*") return score;
137 // Check pawns connection:
138 for (let i = 0; i < V.size.x; i++) {
139 for (let j = 0; j < V.size.y; j++) {
140 if (
141 this.board[i][j] != V.EMPTY &&
142 this.getColor(i, j) == 'b' &&
143 this.getPiece(i, j) == V.PAWN
144 ) {
145 // Exploration "rightward + downward" is enough
146 for (let step of [[1, 0], [0, 1], [1, 1], [-1, 1]]) {
147 let [ii, jj] = [i + step[0], j + step[1]];
148 let kounter = 1;
149 while (
150 V.OnBoard(ii, jj) &&
151 this.board[ii][jj] != V.EMPTY &&
152 this.getColor(ii, jj) == 'b' &&
153 this.getPiece(ii, jj) != V.KING
154 ) {
155 kounter++;
156 ii += step[0];
157 jj += step[1];
158 }
159 if (kounter == 4) return "0-1";
160 }
161 }
162 }
163 }
164 return "*";
165 }
166
167 evalPosition() {
168 let evaluation = 0;
169 // Count white material + check pawns alignments
170 let maxAlign = 0;
171 for (let i = 0; i < V.size.x; i++) {
172 for (let j = 0; j < V.size.y; j++) {
173 if (this.board[i][j] != V.EMPTY) {
174 const piece = this.getPiece(i, j);
175 if (piece != V.KING) {
176 const color = this.getColor(i, j);
177 if (color == 'w') evaluation += V.VALUES[piece];
178 else {
179 // Exploration "rightward + downward" is enough
180 for (let step of [[1, 0], [0, 1], [1, 1], [-1, 1]]) {
181 let [ii, jj] = [i + step[0], j + step[1]];
182 let kounter = 1;
183 while (
184 V.OnBoard(ii, jj) &&
185 this.board[ii][jj] != V.EMPTY &&
186 this.getColor(ii, jj) == 'b' &&
187 this.getPiece(ii, jj) != V.KING
188 ) {
189 kounter++;
190 ii += step[0];
191 jj += step[1];
192 }
193 if (kounter > maxAlign) maxAlign = kounter;
194 }
195 }
196 }
197 }
198 }
199 }
200 // -1 for two aligned pawns, -3 for 3 aligned pawns.
201 if ([1, 2].includes(maxAlign)) maxAlign--;
202 return evaluation - maxAlign;
203 }
204
205 getNotation(move) {
206 if (move.vanish.length == 0) return "@" + V.CoordsToSquare(move.end);
207 return super.getNotation(move);
208 }
209
210 };
211