feat: King can determine if castle is possible

This commit is contained in:
overflowerror 2024-01-07 12:30:22 +01:00
parent 8051485b65
commit ebda02a121
3 changed files with 451 additions and 0 deletions

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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,
));
}
}