1 class CrazyhouseRules
extends ChessRules
5 if (!ChessRules
.IsGoodFen(fen
))
7 const fenParsed
= V
.ParseFen(fen
);
9 if (!fenParsed
.reserve
|| !fenParsed
.reserve
.match(/^[0-9]{10,10}$/))
11 // 6) Check promoted array
12 if (!fenParsed
.promoted
)
14 if (fenParsed
.promoted
== "-")
15 return true; //no promoted piece on board
16 const squares
= fenParsed
.promoted
.split(",");
17 for (let square
of squares
)
19 const c
= V
.SquareToCoords(square
);
20 if (c
.y
< 0 || c
.y
> V
.size
.y
|| isNaN(c
.x
) || c
.x
< 0 || c
.x
> V
.size
.x
)
28 const fenParts
= fen
.split(" ");
30 ChessRules
.ParseFen(fen
),
33 promoted: fenParts
[6],
38 static GenRandInitFen()
40 return ChessRules
.GenRandInitFen() + " 0000000000 -";
45 return super.getFen() + " " + this.getReserveFen() + " " + this.getPromotedFen();
50 let counts
= new Array(10);
51 for (let i
=0; i
<V
.PIECES
.length
-1; i
++) //-1: no king reserve
53 counts
[i
] = this.reserve
["w"][V
.PIECES
[i
]];
54 counts
[5+i
] = this.reserve
["b"][V
.PIECES
[i
]];
56 return counts
.join("");
62 for (let i
=0; i
<V
.size
.x
; i
++)
64 for (let j
=0; j
<V
.size
.y
; j
++)
66 if (this.promoted
[i
][j
])
67 res
+= V
.CoordsToSquare({x:i
,y:j
});
71 res
= res
.slice(0,-1); //remove last comma
77 setOtherVariables(fen
)
79 super.setOtherVariables(fen
);
80 const fenParsed
= V
.ParseFen(fen
);
81 // Also init reserves (used by the interface to show landable pieces)
86 [V
.PAWN
]: parseInt(fenParsed
.reserve
[0]),
87 [V
.ROOK
]: parseInt(fenParsed
.reserve
[1]),
88 [V
.KNIGHT
]: parseInt(fenParsed
.reserve
[2]),
89 [V
.BISHOP
]: parseInt(fenParsed
.reserve
[3]),
90 [V
.QUEEN
]: parseInt(fenParsed
.reserve
[4]),
94 [V
.PAWN
]: parseInt(fenParsed
.reserve
[5]),
95 [V
.ROOK
]: parseInt(fenParsed
.reserve
[6]),
96 [V
.KNIGHT
]: parseInt(fenParsed
.reserve
[7]),
97 [V
.BISHOP
]: parseInt(fenParsed
.reserve
[8]),
98 [V
.QUEEN
]: parseInt(fenParsed
.reserve
[9]),
101 this.promoted
= doubleArray(V
.size
.x
, V
.size
.y
, false);
102 if (fenParsed
.promoted
!= "-")
104 for (let square
of fenParsed
.promoted
.split(","))
106 const [x
,y
] = V
.SquareToCoords(square
);
107 promoted
[x
][y
] = true;
115 return (i
==V
.size
.x
? "w" : "b");
116 return this.board
[i
][j
].charAt(0);
122 return V
.RESERVE_PIECES
[j
];
123 return this.board
[i
][j
].charAt(1);
126 // Used by the interface:
127 getReservePpath(color
, index
)
129 return color
+ V
.RESERVE_PIECES
[index
];
132 // Ordering on reserve pieces
133 static get RESERVE_PIECES()
135 return [V
.PAWN
,V
.ROOK
,V
.KNIGHT
,V
.BISHOP
,V
.QUEEN
];
138 getReserveMoves([x
,y
])
140 const color
= this.turn
;
141 const p
= V
.RESERVE_PIECES
[y
];
142 if (this.reserve
[color
][p
] == 0)
145 const pawnShift
= (p
==V
.PAWN
? 1 : 0);
146 for (let i
=pawnShift
; i
<V
.size
.x
-pawnShift
; i
++)
148 for (let j
=0; j
<V
.size
.y
; j
++)
150 if (this.board
[i
][j
] == V
.EMPTY
)
162 start: {x:x
, y:y
}, //a bit artificial...
172 getPotentialMovesFrom([x
,y
])
176 // Reserves, outside of board: x == sizeX(+1)
177 return this.getReserveMoves([x
,y
]);
180 return super.getPotentialMovesFrom([x
,y
]);
185 let moves
= super.getAllValidMoves();
186 const color
= this.turn
;
187 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
188 moves
= moves
.concat(this.getReserveMoves([V
.size
.x
+(color
=="w"?0:1),i
]));
189 return this.filterValid(moves
);
194 if (!super.atLeastOneMove())
196 const color
= this.turn
;
197 // Search one reserve move
198 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
200 let moves
= this.filterValid(
201 this.getReserveMoves([V
.size
.x
+(this.turn
=="w"?0:1), i
]) );
202 if (moves
.length
> 0)
210 updateVariables(move)
212 super.updateVariables(move);
213 if (move.vanish
.length
== 2 && move.appear
.length
== 2)
214 return; //skip castle
215 const color
= move.appear
[0].c
;
216 if (move.vanish
.length
== 0)
218 this.reserve
[color
][move.appear
[0].p
]--;
221 move.movePromoted
= this.promoted
[move.start
.x
][move.start
.y
];
222 move.capturePromoted
= this.promoted
[move.end
.x
][move.end
.y
]
223 this.promoted
[move.start
.x
][move.start
.y
] = false;
224 this.promoted
[move.end
.x
][move.end
.y
] = move.movePromoted
225 || (move.vanish
[0].p
== V
.PAWN
&& move.appear
[0].p
!= V
.PAWN
);
226 if (move.capturePromoted
)
227 this.reserve
[color
][V
.PAWN
]++;
228 else if (move.vanish
.length
== 2)
229 this.reserve
[color
][move.vanish
[1].p
]++;
232 unupdateVariables(move)
234 super.unupdateVariables(move);
235 if (move.vanish
.length
== 2 && move.appear
.length
== 2)
237 const color
= this.turn
;
238 if (move.vanish
.length
== 0)
240 this.reserve
[color
][move.appear
[0].p
]++;
243 if (move.movePromoted
)
244 this.promoted
[move.start
.x
][move.start
.y
] = true;
245 this.promoted
[move.end
.x
][move.end
.y
] = move.capturePromoted
;
246 if (move.capturePromoted
)
247 this.reserve
[color
][V
.PAWN
]--;
248 else if (move.vanish
.length
== 2)
249 this.reserve
[color
][move.vanish
[1].p
]--;
252 static get SEARCH_DEPTH() { return 2; } //high branching factor
256 let evaluation
= super.evalPosition();
258 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
260 const p
= V
.RESERVE_PIECES
[i
];
261 evaluation
+= this.reserve
["w"][p
] * V
.VALUES
[p
];
262 evaluation
-= this.reserve
["b"][p
] * V
.VALUES
[p
];
269 if (move.vanish
.length
> 0)
270 return super.getNotation(move);
273 (move.appear
[0].p
!= V
.PAWN
? move.appear
[0].p
.toUpperCase() : "");
274 return piece
+ "@" + V
.CoordsToSquare(move.end
);
277 getLongNotation(move)
279 if (move.vanish
.length
> 0)
280 return super.getLongNotation(move);
281 return "@" + V
.CoordsToSquare(move.end
);