/** * Add castling moves if available * * @return array the squares where the king can go **/ protected function addCastlingSquares(King $king, array $squares) { $player = $king->getPlayer(); $rooks = PieceFilter::filterNotMoved(PieceFilter::filterClass(PieceFilter::filterAlive($player->getPieces()), 'Rook')); if (empty($rooks)) { return $squares; } $opponentControlledKeys = $this->getPlayerControlledKeys($player->getOpponent(), true); foreach ($rooks as $rook) { $kingX = $king->getX(); $kingY = $king->getY(); $rookX = $rook->getX(); $dx = $kingX > $rookX ? -1 : 1; $newKingX = 1 === $dx ? 7 : 3; $newRookX = 1 === $dx ? 6 : 4; $possible = true; // Unattacked $rangeMin = min($kingX, $newKingX); $rangeMax = min(8, max($kingX, $newKingX) + 1); for ($_x = $rangeMin; $_x !== $rangeMax; $_x++) { if (in_array(Board::posToKey($_x, $kingY), $opponentControlledKeys)) { $possible = false; break; } } // Unimpeded $rangeMin = min($kingX, $rookX, $newKingX, $newRookX); $rangeMax = min(8, max($kingX, $rookX, $newKingX, $newRookX) + 1); for ($_x = $rangeMin; $_x !== $rangeMax; $_x++) { if ($piece = $this->board->getPieceByKey(Board::posToKey($_x, $kingY))) { if ($piece !== $king && $piece !== $rook) { $possible = false; break; } } } if ($possible) { // If King moves one square or less (Chess variant) if (1 >= abs($kingX - $newKingX)) { $newKingSquare = $rook->getSquare(); } else { $newKingSquare = $this->board->getSquareByPos($newKingX, $kingY); } $squares[] = $newKingSquare; } } return $squares; }
/** * Handle castling **/ protected function castle(King $king, Square $to) { $isKingSide = $this->isCastleKingSide($king, $to); $y = $king->getY(); if ($isKingSide) { $rook = $this->analyser->getCastleRookKingSide($king->getPlayer()); $newRookSquare = $this->board->getSquareByPos(6, $y); $newKingSquare = $this->board->getSquareByPos(7, $y); } else { $rook = $this->analyser->getCastleRookQueenSide($king->getPlayer()); $newRookSquare = $this->board->getSquareByPos(4, $y); $newKingSquare = $this->board->getSquareByPos(3, $y); } if (!$rook) { throw new \LogicException(sprintf('No rook for castle on %s side, king %s to %s', $isKingSide ? 'King' : 'Queen', $king->getSquareKey(), $to->getKey())); } $kingSquare = $king->getSquare(); $rookSquare = $rook->getSquare(); $this->board->castle($king, $rook, $newKingSquare->getX(), $newRookSquare->getX()); $king->setFirstMove($this->game->getTurns()); $rook->setFirstMove($this->game->getTurns()); $this->stack->addEvent(array('type' => 'castling', 'king' => array($kingSquare->getKey(), $newKingSquare->getKey()), 'rook' => array($rookSquare->getKey(), $newRookSquare->getKey()), 'color' => $king->getColor())); }
/** * @depends testBoardCreation */ public function testCleanSquares(Board $board) { $squares = array($board->getSquareByPos(1, 1), null, $board->getSquareByPos(3, 8), $board->getSquareByPos(3, 8)); $cleanSquares = array($board->getSquareByPos(1, 1), $board->getSquareByPos(3, 8)); $this->assertSame($cleanSquares, $board->cleanSquares($squares)); }
protected function canCastle(King $king, $relativeX) { $_x = $king->getX() + $relativeX; return $_x > 0 && $_x < 9 && !$king->hasMoved() && ($rook = $this->board->getSquareByPos($king->getX() + $relativeX, $king->getY())->getPiece()) && ($rook->isClass('Rook') && !$rook->hasMoved()); }