mirror of
https://github.com/lichess-org/dartchess.git
synced 2026-05-26 13:51:01 +00:00
Make Position completely immutable by switching pockets implementation
This commit is contained in:
+27
-54
@@ -213,69 +213,56 @@ class Setup {
|
||||
/// Pockets (captured pieces) in chess variants like [Crazyhouse].
|
||||
@immutable
|
||||
class Pockets {
|
||||
const Pockets({required BySide<ByRole<int>> value}) : _value = value;
|
||||
const Pockets._(this._value);
|
||||
|
||||
final BySide<ByRole<int>> _value;
|
||||
// Bitfield: 5 bits per (side, role) slot.
|
||||
// Offset = side.index * 30 + role.index * 5. Total: 60 bits.
|
||||
final int _value;
|
||||
|
||||
/// An empty pocket.
|
||||
static const empty = Pockets(value: _emptyPocketsBySide);
|
||||
static const empty = Pockets._(0);
|
||||
|
||||
/// Gets the total number of pieces in the pocket.
|
||||
int get size => _value.values
|
||||
.fold(0, (acc, e) => acc + e.values.fold(0, (acc, e) => acc + e));
|
||||
static int _offset(Side side, Role role) => side.index * 30 + role.index * 5;
|
||||
|
||||
/// Gets the number of pieces of that [Side] and [Role] in the pocket.
|
||||
int of(Side side, Role role) {
|
||||
return _value[side]![role]!;
|
||||
}
|
||||
int of(Side side, Role role) => (_value >> _offset(side, role)) & 0x1F;
|
||||
|
||||
/// Gets the total number of pieces in the pocket.
|
||||
int get size => Side.values.fold(
|
||||
0,
|
||||
(acc, s) => acc + Role.values.fold(0, (acc2, r) => acc2 + of(s, r)),
|
||||
);
|
||||
|
||||
/// Counts the number of pieces by [Role].
|
||||
int count(Role role) {
|
||||
return _value[Side.white]![role]! + _value[Side.black]![role]!;
|
||||
}
|
||||
int count(Role role) => of(Side.white, role) + of(Side.black, role);
|
||||
|
||||
/// Checks whether this side has at least 1 quality (any piece but a pawn).
|
||||
bool hasQuality(Side side) {
|
||||
final bySide = _value[side]!;
|
||||
return bySide[Role.knight]! > 0 ||
|
||||
bySide[Role.bishop]! > 0 ||
|
||||
bySide[Role.rook]! > 0 ||
|
||||
bySide[Role.queen]! > 0 ||
|
||||
bySide[Role.king]! > 0;
|
||||
}
|
||||
bool hasQuality(Side side) =>
|
||||
of(side, Role.knight) > 0 ||
|
||||
of(side, Role.bishop) > 0 ||
|
||||
of(side, Role.rook) > 0 ||
|
||||
of(side, Role.queen) > 0 ||
|
||||
of(side, Role.king) > 0;
|
||||
|
||||
/// Checks whether this side has at least 1 pawn.
|
||||
bool hasPawn(Side side) {
|
||||
return _value[side]![Role.pawn]! > 0;
|
||||
}
|
||||
bool hasPawn(Side side) => of(side, Role.pawn) > 0;
|
||||
|
||||
/// Increments the number of pieces in the pocket of that [Side] and [Role].
|
||||
Pockets increment(Side side, Role role) {
|
||||
final newPocket = {..._value[side]!, role: of(side, role) + 1};
|
||||
return Pockets(value: {..._value, side: newPocket});
|
||||
}
|
||||
Pockets increment(Side side, Role role) =>
|
||||
Pockets._(_value + (1 << _offset(side, role)));
|
||||
|
||||
/// Decrements the number of pieces in the pocket of that [Side] and [Role].
|
||||
Pockets decrement(Side side, Role role) {
|
||||
final newPocket = {..._value[side]!, role: of(side, role) - 1};
|
||||
return Pockets(value: {..._value, side: newPocket});
|
||||
}
|
||||
Pockets decrement(Side side, Role role) =>
|
||||
Pockets._(_value - (1 << _offset(side, role)));
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! Pockets) return false;
|
||||
for (final side in Side.values) {
|
||||
for (final role in Role.values) {
|
||||
if (of(side, role) != other.of(side, role)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return other is Pockets && other._value == _value;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll(
|
||||
Side.values.expand((s) => Role.values.map((r) => of(s, r))));
|
||||
int get hashCode => _value.hashCode;
|
||||
}
|
||||
|
||||
Pockets _parsePockets(String pocketPart) {
|
||||
@@ -401,17 +388,3 @@ int _nthIndexOf(String haystack, String needle, int nth) {
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
const ByRole<int> _emptyPocket = {
|
||||
Role.pawn: 0,
|
||||
Role.knight: 0,
|
||||
Role.bishop: 0,
|
||||
Role.rook: 0,
|
||||
Role.queen: 0,
|
||||
Role.king: 0,
|
||||
};
|
||||
|
||||
const BySide<ByRole<int>> _emptyPocketsBySide = {
|
||||
Side.white: _emptyPocket,
|
||||
Side.black: _emptyPocket,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user