1 import { ChessRules
} from "@/base_rules";
2 import { randInt
} from "@/utils/alea";
4 export class MonsterRules
extends ChessRules
{
5 static IsGoodFlags(flags
) {
6 // Only black can castle
7 return !!flags
.match(/^[a-z]{2,2}$/);
10 static GenRandInitFen(randomness
) {
11 if (randomness
== 2) randomness
--;
12 const fen
= ChessRules
.GenRandInitFen(randomness
);
14 // 26 first chars are 6 rows + 6 slashes
16 // En passant available, and "half-castle"
17 .concat("1PPPPPP1/4K3 w 0 ")
18 .concat(fen
.substr(-6, 2))
24 return this.castleFlags
['b'].map(V
.CoordToColumn
).join("");
28 this.castleFlags
= { 'b': [-1, -1] };
29 for (let i
= 0; i
< 2; i
++)
30 this.castleFlags
['b'][i
] = V
.ColumnToCoord(fenflags
.charAt(i
));
33 setOtherVariables(fen
) {
34 super.setOtherVariables(fen
);
38 getPotentialKingMoves([x
, y
]) {
39 if (this.getColor(x
, y
) == 'b') return super.getPotentialKingMoves([x
, y
]);
40 // White doesn't castle:
41 return this.getSlideNJumpMoves(
43 V
.steps
[V
.ROOK
].concat(V
.steps
[V
.BISHOP
]),
48 isAttacked(sq
, color
, castling
) {
49 // Goal is king capture => no checks
62 const color
= this.turn
;
63 if (this.kingPos
[color
][0] < 0) return (color
== 'w' ? "0-1" : "1-0");
68 move.flags
= JSON
.stringify(this.aggregateFlags());
69 if (this.turn
== 'b' || this.subTurn
== 2)
70 this.epSquares
.push(this.getEpSquare(move));
71 else this.epSquares
.push(null);
72 V
.PlayOnBoard(this.board
, move);
73 if (this.turn
== 'w') {
74 if (this.subTurn
== 1) this.movesCount
++;
76 this.subTurn
= 3 - this.subTurn
;
84 updateCastleFlags(move, piece
) {
85 // Only black can castle:
87 if (piece
== V
.KING
&& move.appear
[0].c
== 'b')
88 this.castleFlags
['b'] = [8, 8];
90 move.start
.x
== firstRank
&&
91 this.castleFlags
['b'].includes(move.start
.y
)
93 const flagIdx
= (move.start
.y
== this.castleFlags
['b'][0] ? 0 : 1);
94 this.castleFlags
['b'][flagIdx
] = 8;
97 move.end
.x
== firstRank
&&
98 this.castleFlags
['b'].includes(move.end
.y
)
100 const flagIdx
= (move.end
.y
== this.castleFlags
['b'][0] ? 0 : 1);
101 this.castleFlags
['b'][flagIdx
] = 8;
106 // Definition of 'c' in base class doesn't work:
107 const c
= move.vanish
[0].c
;
108 const piece
= move.vanish
[0].p
;
110 this.kingPos
[c
] = [move.appear
[0].x
, move.appear
[0].y
];
111 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
112 // Opponent's king is captured, game over
113 this.kingPos
[move.vanish
[1].c
] = [-1, -1];
114 this.updateCastleFlags(move, piece
);
118 this.epSquares
.pop();
119 this.disaggregateFlags(JSON
.parse(move.flags
));
120 V
.UndoOnBoard(this.board
, move);
121 if (this.turn
== 'w') {
122 if (this.subTurn
== 2) this.subTurn
= 1;
123 else this.turn
= 'b';
134 if (move.vanish
.length
== 2 && move.vanish
[1].p
== V
.KING
)
135 // Opponent's king was captured
136 this.kingPos
[move.vanish
[1].c
] = [move.vanish
[1].x
, move.vanish
[1].y
];
137 super.postUndo(move);
140 // Custom search at depth 1(+1)
142 const getBestWhiteMove
= (terminal
) => {
143 // Generate all sequences of 2-moves
144 let moves1
= this.getAllValidMoves();
145 moves1
.forEach(m1
=> {
146 m1
.eval
= -V
.INFINITY
;
149 if (!!terminal
) m1
.eval
= this.evalPosition();
151 const moves2
= this.getAllValidMoves();
152 moves2
.forEach(m2
=> {
154 const eval2
= this.evalPosition() + 0.05 - Math
.random() / 10;
156 if (eval2
> m1
.eval
) {
164 moves1
.sort((a
, b
) => b
.eval
- a
.eval
);
166 // The move itself doesn't matter, only its eval:
168 let candidates
= [0];
171 i
< moves1
.length
&& moves1
[i
].eval
== moves1
[0].eval
;
176 const idx
= candidates
[randInt(candidates
.length
)];
177 const move2
= moves1
[idx
].move2
;
178 delete moves1
[idx
]["move2"];
179 return [moves1
[idx
], move2
];
182 const getBestBlackMove
= () => {
183 let moves
= this.getAllValidMoves();
187 const evalM
= getBestWhiteMove("terminal").eval
189 if (evalM
< m
.eval
) m
.eval
= evalM
;
191 moves
.sort((a
, b
) => a
.eval
- b
.eval
);
192 let candidates
= [0];
195 i
< moves
.length
&& moves
[i
].eval
== moves
[0].eval
;
200 const idx
= candidates
[randInt(candidates
.length
)];
204 const color
= this.turn
;
205 return (color
== 'w' ? getBestWhiteMove() : getBestBlackMove());