mirror of
https://github.com/sigmasternchen/php-chess
synced 2025-03-14 23:58:53 +00:00
feat: King can determine if castle is possible
This commit is contained in:
parent
8051485b65
commit
ebda02a121
3 changed files with 451 additions and 0 deletions
|
@ -35,6 +35,10 @@ class FieldBitMap {
|
|||
}
|
||||
}
|
||||
|
||||
public function invert(): FieldBitMap {
|
||||
return new FieldBitMap(~$this->map);
|
||||
}
|
||||
|
||||
public function intersect(FieldBitMap $map): FieldBitMap {
|
||||
return new FieldBitMap($this->map & $map->map);
|
||||
}
|
||||
|
|
|
@ -32,4 +32,31 @@ class King extends Piece {
|
|||
public function isInCheck(FieldBitMap $captureable): bool {
|
||||
return $captureable->has($this->position);
|
||||
}
|
||||
|
||||
public function canCastle(
|
||||
FieldBitMap $occupied,
|
||||
FieldBitMap $captureable,
|
||||
FieldBitMap $threatened,
|
||||
Rook $rook,
|
||||
): bool {
|
||||
if ($this->position->rank != $rook->position->rank) {
|
||||
return false;
|
||||
}
|
||||
if ($this->hasMoved || $rook->hasMoved) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$increment = $rook->position->file <=> $this->position->file;
|
||||
for ($file = $this->position->file + $increment; $file != $rook->position->file; $file += $increment) {
|
||||
$square = new Position($file, $this->position->rank);
|
||||
if ($occupied->has($square) || $captureable->has($square)) {
|
||||
return false;
|
||||
}
|
||||
if (abs($file - $this->position->file) <= 2 && $threatened->has($square)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -99,4 +99,424 @@ final class KingTest extends TestCase {
|
|||
]))
|
||||
);
|
||||
}
|
||||
|
||||
public function testCanCastle_long() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertTrue($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumOccupiedMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_short() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(7, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(6, 0),
|
||||
new Position(5, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertTrue($king->canCastle(
|
||||
$maximumMap,
|
||||
$maximumMap,
|
||||
$maximumMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_occupied1() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
public function testCanCastle_long_occupied2() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_occupied3() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_captureable1() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_captureable2() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_captureable3() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_threatened2() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_threatened3() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_kingMoved() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE,
|
||||
true
|
||||
);
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
|
||||
public function testCanCastle_long_rookMoved() {
|
||||
$king = new King(
|
||||
new Position(4, 0),
|
||||
Side::WHITE,
|
||||
);
|
||||
$king->move(new Position(4, 0));
|
||||
|
||||
$rook = new Rook(
|
||||
new Position(0, 0),
|
||||
Side::WHITE,
|
||||
true,
|
||||
);
|
||||
|
||||
$maximumOccupiedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumCaptureableMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(1, 0),
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
$maximumThreatenedMap =
|
||||
FieldBitMap::full()->intersect((new FieldBitMap([
|
||||
new Position(2, 0),
|
||||
new Position(3, 0),
|
||||
]))->invert());
|
||||
|
||||
$this->assertFalse($king->canCastle(
|
||||
$maximumOccupiedMap,
|
||||
$maximumCaptureableMap,
|
||||
$maximumThreatenedMap,
|
||||
$rook,
|
||||
));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue