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