1 import { ChessRules
, Move
, PiPo
} from "@/base_rules";
3 export class Align4Rules
extends ChessRules
{
17 static GenRandInitFen(options
) {
18 const baseFen
= ChessRules
.GenRandInitFen(
19 { randomness: (options
.random
? 1 : 0) });
20 return "4k3/8" + baseFen
.substring(17, 50) + " -";
27 static get RESERVE_PIECES() {
28 return [V
.PAWN
]; //only black pawns
32 if (i
>= V
.size
.x
) return "b";
33 return this.board
[i
][j
].charAt(0);
37 if (i
>= V
.size
.x
) return V
.PAWN
;
38 return this.board
[i
][j
].charAt(1);
41 static IsGoodFlags(flags
) {
42 // Only white can castle
43 return !!flags
.match(/^[a-z]{2,2}$/);
47 return this.castleFlags
['w'].map(V
.CoordToColumn
).join("");
51 this.castleFlags
= { 'w': [-1, -1] };
52 for (let i
= 0; i
< 2; i
++)
53 this.castleFlags
['w'][i
] = V
.ColumnToCoord(fenflags
.charAt(i
));
56 setOtherVariables(fen
) {
57 super.setOtherVariables(fen
);
58 this.reserve
= { b: { [V
.PAWN
]: 1 } };
62 if (this.turn
!= 'b') return [];
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
) {
77 start: { x: 9, y: 0 },
87 getPotentialMovesFrom(sq
) {
88 if (sq
[0] >= V
.size
.x
) return this.getReserveMoves();
89 return super.getPotentialMovesFrom(sq
);
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);
101 super.getAllValidMoves().concat(
102 super.filterValid(this.getReserveMoves()))
107 if (super.atLeastOneMove()) return true;
108 // Search one reserve move
109 if (this.filterValid(this.getReserveMoves()).length
> 0) return true;
113 updateCastleFlags(move, piece
) {
114 // Only white can castle:
116 if (piece
== V
.KING
&& move.appear
[0].c
== 'w')
117 this.castleFlags
['w'] = [8, 8];
119 move.start
.x
== firstRank
&&
120 this.castleFlags
['w'].includes(move.start
.y
)
122 const flagIdx
= (move.start
.y
== this.castleFlags
['w'][0] ? 0 : 1);
123 this.castleFlags
['w'][flagIdx
] = 8;
126 move.end
.x
== firstRank
&&
127 this.castleFlags
['w'].includes(move.end
.y
)
129 const flagIdx
= (move.end
.y
== this.castleFlags
['w'][0] ? 0 : 1);
130 this.castleFlags
['w'][flagIdx
] = 8;
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
++) {
141 this.board
[i
][j
] != V
.EMPTY
&&
142 this.getColor(i
, j
) == 'b' &&
143 this.getPiece(i
, j
) == V
.PAWN
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]];
151 this.board
[ii
][jj
] != V
.EMPTY
&&
152 this.getColor(ii
, jj
) == 'b' &&
153 this.getPiece(ii
, jj
) != V
.KING
159 if (kounter
== 4) return "0-1";
169 // Count white material + check pawns alignments
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
];
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]];
185 this.board
[ii
][jj
] != V
.EMPTY
&&
186 this.getColor(ii
, jj
) == 'b' &&
187 this.getPiece(ii
, jj
) != V
.KING
193 if (kounter
> maxAlign
) maxAlign
= kounter
;
200 // -1 for two aligned pawns, -3 for 3 aligned pawns.
201 if ([1, 2].includes(maxAlign
)) maxAlign
--;
202 return evaluation
- maxAlign
;
206 if (move.vanish
.length
== 0) return "@" + V
.CoordsToSquare(move.end
);
207 return super.getNotation(move);