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 fenpromoted
= fenParsed
.promoted
;
15 if (fenpromoted
== "-")
16 return true; //no promoted piece on board
17 const squares
= fenpromoted
.split(",");
18 for (let square
of squares
)
20 const c
= V
.SquareToCoords(square
);
21 if (c
.y
< 0 || c
.y
> V
.size
.y
|| isNaN(c
.x
) || c
.x
< 0 || c
.x
> V
.size
.x
)
29 const fenParts
= fen
.split(" ");
31 ChessRules
.ParseFen(fen
),
34 promoted: fenParts
[5],
39 static GenRandInitFen()
41 return ChessRules
.GenRandInitFen() + " 0000000000 -";
46 return super.getFen() + " " + this.getReserveFen() + " " + this.getPromotedFen();
51 let counts
= _
.map(_
.range(10), 0);
52 for (let i
=0; i
<V
.PIECES
.length
; i
++)
54 counts
[i
] = this.reserve
["w"][V
.PIECES
[i
]];
55 counts
[5+i
] = this.reserve
["b"][V
.PIECES
[i
]];
57 return counts
.join("");
63 for (let i
=0; i
<V
.size
.x
; i
++)
65 for (let j
=0; j
<V
.size
.y
; j
++)
67 if (this.promoted
[i
][j
])
68 res
+= V
.CoordsToSquare({x:i
,y:j
});
72 res
= res
.slice(0,-1); //remove last comma
78 setOtherVariables(fen
)
80 super.setOtherVariables(fen
);
81 const fenParsed
= V
.ParseFen(fen
);
82 // Also init reserves (used by the interface to show landable pieces)
87 [V
.PAWN
]: parseInt(fenParsed
.reserve
[0]),
88 [V
.ROOK
]: parseInt(fenParsed
.reserve
[1]),
89 [V
.KNIGHT
]: parseInt(fenParsed
.reserve
[2]),
90 [V
.BISHOP
]: parseInt(fenParsed
.reserve
[3]),
91 [V
.QUEEN
]: parseInt(fenParsed
.reserve
[4]),
95 [V
.PAWN
]: parseInt(fenParsed
.reserve
[5]),
96 [V
.ROOK
]: parseInt(fenParsed
.reserve
[6]),
97 [V
.KNIGHT
]: parseInt(fenParsed
.reserve
[7]),
98 [V
.BISHOP
]: parseInt(fenParsed
.reserve
[8]),
99 [V
.QUEEN
]: parseInt(fenParsed
.reserve
[9]),
102 this.promoted
= doubleArray(V
.size
.x
, V
.size
.y
, false);
103 if (fenParsed
.promoted
!= "-")
105 for (let square
of fenParsed
.promoted
.split(","))
107 const [x
,y
] = V
.SquareToCoords(square
);
108 promoted
[x
][y
] = true;
116 return (i
==V
.size
.x
? "w" : "b");
117 return this.board
[i
][j
].charAt(0);
123 return V
.RESERVE_PIECES
[j
];
124 return this.board
[i
][j
].charAt(1);
127 // Used by the interface:
128 getReservePpath(color
, index
)
130 return color
+ V
.RESERVE_PIECES
[index
];
133 // Ordering on reserve pieces
134 static get RESERVE_PIECES()
136 return [V
.PAWN
,V
.ROOK
,V
.KNIGHT
,V
.BISHOP
,V
.QUEEN
];
139 getReserveMoves([x
,y
])
141 const color
= this.turn
;
142 const p
= V
.RESERVE_PIECES
[y
];
143 if (this.reserve
[color
][p
] == 0)
146 const pawnShift
= (p
==V
.PAWN
? 1 : 0);
147 for (let i
=pawnShift
; i
<V
.size
.x
-pawnShift
; i
++)
149 for (let j
=0; j
<V
.size
.y
; j
++)
151 if (this.board
[i
][j
] == V
.EMPTY
)
163 start: {x:x
, y:y
}, //a bit artificial...
173 getPotentialMovesFrom([x
,y
])
177 // Reserves, outside of board: x == sizeX(+1)
178 return this.getReserveMoves([x
,y
]);
181 return super.getPotentialMovesFrom([x
,y
]);
186 let moves
= super.getAllValidMoves();
187 const color
= this.turn
;
188 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
189 moves
= moves
.concat(this.getReserveMoves([V
.size
.x
+(color
=="w"?0:1),i
]));
190 return this.filterValid(moves
);
195 if (!super.atLeastOneMove())
197 const color
= this.turn
;
198 // Search one reserve move
199 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
201 let moves
= this.filterValid(
202 this.getReserveMoves([V
.size
.x
+(this.turn
=="w"?0:1), i
]) );
203 if (moves
.length
> 0)
211 updateVariables(move)
213 super.updateVariables(move);
214 if (move.vanish
.length
== 2 && move.appear
.length
== 2)
215 return; //skip castle
216 const color
= this.turn
;
217 if (move.vanish
.length
== 0)
219 this.reserve
[color
][move.appear
[0].p
]--;
222 move.movePromoted
= this.promoted
[move.start
.x
][move.start
.y
];
223 move.capturePromoted
= this.promoted
[move.end
.x
][move.end
.y
]
224 this.promoted
[move.start
.x
][move.start
.y
] = false;
225 this.promoted
[move.end
.x
][move.end
.y
] = move.movePromoted
226 || (move.vanish
[0].p
== V
.PAWN
&& move.appear
[0].p
!= V
.PAWN
);
227 if (move.capturePromoted
)
228 this.reserve
[color
][V
.PAWN
]++;
229 else if (move.vanish
.length
== 2)
230 this.reserve
[color
][move.vanish
[1].p
]++;
233 unupdateVariables(move)
235 super.unupdateVariables(move);
236 if (move.vanish
.length
== 2 && move.appear
.length
== 2)
238 const color
= this.turn
;
239 if (move.vanish
.length
== 0)
241 this.reserve
[color
][move.appear
[0].p
]++;
244 if (move.movePromoted
)
245 this.promoted
[move.start
.x
][move.start
.y
] = true;
246 this.promoted
[move.end
.x
][move.end
.y
] = move.capturePromoted
;
247 if (move.capturePromoted
)
248 this.reserve
[color
][V
.PAWN
]--;
249 else if (move.vanish
.length
== 2)
250 this.reserve
[color
][move.vanish
[1].p
]--;
253 static get SEARCH_DEPTH() { return 2; } //high branching factor
257 let evaluation
= super.evalPosition();
259 for (let i
=0; i
<V
.RESERVE_PIECES
.length
; i
++)
261 const p
= V
.RESERVE_PIECES
[i
];
262 evaluation
+= this.reserve
["w"][p
] * V
.VALUES
[p
];
263 evaluation
-= this.reserve
["b"][p
] * V
.VALUES
[p
];
270 if (move.vanish
.length
> 0)
271 return super.getNotation(move);
274 (move.appear
[0].p
!= V
.PAWN
? move.appear
[0].p
.toUpperCase() : "");
275 return piece
+ "@" + V
.CoordsToSquare(move.end
);
278 getLongNotation(move)
280 if (move.vanish
.length
> 0)
281 return super.getLongNotation(move);
282 return "@" + V
.CoordsToSquare(move.end
);
286 const VariantRules
= CrazyhouseRules
;