ec903c2fbdc056c53ced6c352111f3d649bc5c21
1 import { ChessRules
, PiPo
, Move
} from "@/base_rules";
2 import { ArrayFun
} from "@/utils/array";
4 export const VariantRules
= class CrazyhouseRules
extends ChessRules
8 if (!ChessRules
.IsGoodFen(fen
))
10 const fenParsed
= V
.ParseFen(fen
);
12 if (!fenParsed
.reserve
|| !fenParsed
.reserve
.match(/^[0-9]{10,10}$/))
14 // 6) Check promoted array
15 if (!fenParsed
.promoted
)
17 if (fenParsed
.promoted
== "-")
18 return true; //no promoted piece on board
19 const squares
= fenParsed
.promoted
.split(",");
20 for (let square
of squares
)
22 const c
= V
.SquareToCoords(square
);
23 if (c
.y
< 0 || c
.y
> V
.size
.y
|| isNaN(c
.x
) || c
.x
< 0 || c
.x
> V
.size
.x
)
31 const fenParts
= fen
.split(" ");
33 ChessRules
.ParseFen(fen
),
36 promoted: fenParts
[6],
41 static GenRandInitFen()
43 return ChessRules
.GenRandInitFen() + " 0000000000 -";
48 return super.getFen() + " " + this.getReserveFen() + " " + this.getPromotedFen();
53 let counts
= new Array(10);
54 for (let i
=0; i
<V
.PIECES
.length
-1; i
++) //-1: no king reserve
56 counts
[i
] = this.reserve
["w"][V
.PIECES
[i
]];
57 counts
[5+i
] = this.reserve
["b"][V
.PIECES
[i
]];
59 return counts
.join("");
65 for (let i
=0; i
<V
.size
.x
; i
++)
67 for (let j
=0; j
<V
.size
.y
; j
++)
69 if (this.promoted
[i
][j
])
70 res
+= V
.CoordsToSquare({x:i
,y:j
});
74 res
= res
.slice(0,-1); //remove last comma
80 setOtherVariables(fen
)
82 super.setOtherVariables(fen
);
83 const fenParsed
= V
.ParseFen(fen
);
84 // Also init reserves (used by the interface to show landable pieces)
89 [V
.PAWN
]: parseInt(fenParsed
.reserve
[0]),
90 [V
.ROOK
]: parseInt(fenParsed
.reserve
[1]),
91 [V
.KNIGHT
]: parseInt(fenParsed
.reserve
[2]),
92 [V
.BISHOP
]: parseInt(fenParsed
.reserve
[3]),
93 [V
.QUEEN
]: parseInt(fenParsed
.reserve
[4]),
97 [V
.PAWN
]: parseInt(fenParsed
.reserve
[5]),
98 [V
.ROOK
]: parseInt(fenParsed
.reserve
[6]),
99 [V
.KNIGHT
]: parseInt(fenParsed
.reserve
[7]),
100 [V
.BISHOP
]: parseInt(fenParsed
.reserve
[8]),
101 [V
.QUEEN
]: parseInt(fenParsed
.reserve
[9]),
104 this.promoted
= ArrayFun
.init(V
.size
.x
, V
.size
.y
, false);
105 if (fenParsed
.promoted
!= "-")
107 for (let square
of fenParsed
.promoted
.split(","))
109 const [x
,y
] = V
.SquareToCoords(square
);
110 promoted
[x
][y
] = true;
118 return (i
==V
.size
.x
? "w" : "b");
119 return this.board
[i
][j
].charAt(0);
125 return V
.RESERVE_PIECES
[j
];
126 return this.board
[i
][j
].charAt(1);
129 // Used by the interface:
130 getReservePpath(color
, index
)
132 return color
+ V
.RESERVE_PIECES
[index
];
135 // Ordering on reserve pieces
136 static get RESERVE_PIECES()
138 return [V
.PAWN
,V
.ROOK
,V
.KNIGHT
,V
.BISHOP
,V
.QUEEN
];
141 getReserveMoves([x
,y
])
143 const color
= this.turn
;
144 const p
= V
.RESERVE_PIECES
[y
];
145 if (this.reserve
[color
][p
] == 0)
148 const pawnShift
= (p
==V
.PAWN
? 1 : 0);
149 for (let i
=pawnShift
; i
<V
.size
.x
-pawnShift
; i
++)
151 for (let j
=0; j
<V
.size
.y
; j
++)
153 if (this.board
[i
][j
] == V
.EMPTY
)
165 start: {x:x
, y:y
}, //a bit artificial...
175 getPotentialMovesFrom([x
,y
])
179 // Reserves, outside of board: x == sizeX(+1)
180 return this.getReserveMoves([x
,y
]);
183 return super.getPotentialMovesFrom([x
,y
]);
188 let moves
= super.getAllValidMoves();
189 const color
= this.turn
;
190 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
191 moves
= moves
.concat(this.getReserveMoves([V
.size
.x
+(color
=="w"?0:1),i
]));
192 return this.filterValid(moves
);
197 if (!super.atLeastOneMove())
199 const color
= this.turn
;
200 // Search one reserve move
201 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
203 let moves
= this.filterValid(
204 this.getReserveMoves([V
.size
.x
+(this.turn
=="w"?0:1), i
]) );
205 if (moves
.length
> 0)
213 updateVariables(move)
215 super.updateVariables(move);
216 if (move.vanish
.length
== 2 && move.appear
.length
== 2)
217 return; //skip castle
218 const color
= move.appear
[0].c
;
219 if (move.vanish
.length
== 0)
221 this.reserve
[color
][move.appear
[0].p
]--;
224 move.movePromoted
= this.promoted
[move.start
.x
][move.start
.y
];
225 move.capturePromoted
= this.promoted
[move.end
.x
][move.end
.y
]
226 this.promoted
[move.start
.x
][move.start
.y
] = false;
227 this.promoted
[move.end
.x
][move.end
.y
] = move.movePromoted
228 || (move.vanish
[0].p
== V
.PAWN
&& move.appear
[0].p
!= V
.PAWN
);
229 if (move.capturePromoted
)
230 this.reserve
[color
][V
.PAWN
]++;
231 else if (move.vanish
.length
== 2)
232 this.reserve
[color
][move.vanish
[1].p
]++;
235 unupdateVariables(move)
237 super.unupdateVariables(move);
238 if (move.vanish
.length
== 2 && move.appear
.length
== 2)
240 const color
= this.turn
;
241 if (move.vanish
.length
== 0)
243 this.reserve
[color
][move.appear
[0].p
]++;
246 if (move.movePromoted
)
247 this.promoted
[move.start
.x
][move.start
.y
] = true;
248 this.promoted
[move.end
.x
][move.end
.y
] = move.capturePromoted
;
249 if (move.capturePromoted
)
250 this.reserve
[color
][V
.PAWN
]--;
251 else if (move.vanish
.length
== 2)
252 this.reserve
[color
][move.vanish
[1].p
]--;
255 static get SEARCH_DEPTH() { return 2; } //high branching factor
259 let evaluation
= super.evalPosition();
261 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
263 const p
= V
.RESERVE_PIECES
[i
];
264 evaluation
+= this.reserve
["w"][p
] * V
.VALUES
[p
];
265 evaluation
-= this.reserve
["b"][p
] * V
.VALUES
[p
];
272 if (move.vanish
.length
> 0)
273 return super.getNotation(move);
276 (move.appear
[0].p
!= V
.PAWN
? move.appear
[0].p
.toUpperCase() : "");
277 return piece
+ "@" + V
.CoordsToSquare(move.end
);
280 getLongNotation(move)
282 if (move.vanish
.length
> 0)
283 return super.getLongNotation(move);
284 return "@" + V
.CoordsToSquare(move.end
);