Пример #1
0
 /**
  * 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();
         $dx = $kingX > $rook->getX() ? -1 : 1;
         $possible = true;
         foreach (array($kingX + $dx, $kingX + 2 * $dx) as $_x) {
             $key = Board::postoKey($_x, $kingY);
             if ($this->board->hasPieceByKey($key) || in_array($key, $opponentControlledKeys)) {
                 $possible = false;
                 break;
             }
         }
         if ($possible) {
             if (-1 === $dx && $this->board->hasPieceByKey(Board::postoKey($kingX - 3, $kingY))) {
             } else {
                 $squares[] = $this->board->getSquareByKey($key);
             }
         }
     }
     return $squares;
 }
Пример #2
0
 /**
  * Move a piece on the board
  * Performs several validation before applying the move 
  * 
  * @param mixed $notation Valid algebraic notation (e.g. "a2 a4") 
  * @return void
  */
 public function move($notation, array $options = array())
 {
     list($from, $to) = explode(' ', $notation);
     if (!($from = $this->board->getSquareByKey($from))) {
         throw new \InvalidArgumentException('Square ' . $from . ' does not exist');
     }
     if (!($to = $this->board->getSquareByKey($to))) {
         throw new \InvalidArgumentException('Square ' . $to . ' does not exist');
     }
     if (!($piece = $from->getPiece())) {
         throw new \InvalidArgumentException('No piece on ' . $from);
     }
     if (!$piece->getPlayer()->isMyTurn()) {
         throw new \LogicException('Can not play ' . $from . ' ' . $to . ' - Not ' . $piece->getColor() . ' player turn');
     }
     $possibleMoves = $this->analyser->getPiecePossibleMoves($piece);
     if (!$possibleMoves) {
         throw new \LogicException($piece . ' can not move');
     }
     if (!in_array($to->getKey(), $possibleMoves)) {
         throw new \LogicException($piece . ' can not go to ' . $to . ' (' . implode(',', $possibleMoves) . ')');
     }
     if ($killed = $to->getPiece()) {
         $killed->setIsDead(true);
         $this->board->remove($killed);
     }
     $this->board->move($piece, $to->getX(), $to->getY());
     if ($this->stack) {
         $this->stack->add(array('type' => 'move', 'from' => $from->getKey(), 'to' => $to->getKey()));
     }
     if (null === $piece->getFirstMove()) {
         $piece->setFirstMove($this->game->getTurns());
     }
     // casting?
     if ($piece instanceof King && 2 === abs($from->getX() - $to->getX())) {
         $this->castling($piece, $to);
     }
     // promotion?
     if ($piece instanceof Pawn && $to->getY() === ($piece->getPlayer()->isWhite() ? 8 : 1)) {
         $this->promotion($piece, $options);
     }
     // enpassant?
     if ($piece instanceof Pawn && $to->getX() !== $from->getX() && !$killed) {
         $this->enpassant($piece, $to);
     }
 }
Пример #3
0
 public function getSquare()
 {
     return $this->board->getSquareByKey(Board::posToKey($this->x, $this->y));
 }
Пример #4
0
 /**
  * @depends testBoardCreation
  */
 public function testGetSquareByPos(Board $board)
 {
     $square = $board->getSquareByPos(1, 1);
     $this->assertSame($board->getSquareByKey('a1'), $square);
 }
Пример #5
0
 /**
  * Move a piece on the board
  * Performs several validation before applying the move
  *
  * @param mixed $notation Valid algebraic notation (e.g. "a2 a4")
  * @return string PGN notation of the move
  */
 public function move($notation, array $options = array())
 {
     list($fromKey, $toKey) = explode(' ', $notation);
     if (!$fromKey || !$toKey) {
         throw new \InvalidArgumentException(sprintf('Manipulator:move game:%s, Invalid internal move notation "%s"', $this->game->getId(), $notation));
     }
     if (!($from = $this->board->getSquareByKey($fromKey))) {
         throw new \InvalidArgumentException(sprintf('Manipulator:move game:%s, Square ' . $fromKey . ' does not exist', $this->game->getId()));
     }
     if (!($to = $this->board->getSquareByKey($toKey))) {
         throw new \InvalidArgumentException(sprintf('Manipulator:move game:%s, Square ' . $toKey . ' does not exist', $this->game->getId()));
     }
     if (!($piece = $from->getPiece())) {
         throw new \InvalidArgumentException(sprintf('Manipulator:move game:%s, No piece on ' . $from, $this->game->getId()));
     }
     $player = $piece->getPlayer();
     if (!$player->isMyTurn()) {
         throw new \LogicException(sprintf('Manipulator:move game:%s, Can not play ' . $from . ' ' . $to . ' - Not ' . $piece->getColor() . ' player turn', $this->game->getId()));
     }
     $pieceClass = $piece->getClass();
     $isPlayerKingAttacked = $this->analyser->isKingAttacked($player);
     $playerPossibleMoves = $this->analyser->getPlayerPossibleMoves($player, $isPlayerKingAttacked);
     $possibleMoves = isset($playerPossibleMoves[$fromKey]) ? $playerPossibleMoves[$fromKey] : false;
     if (!$possibleMoves) {
         throw new \LogicException(sprintf('Manipulator:move game:%s, %s can not move', $this->game->getId(), $piece));
     }
     if (!in_array($toKey, $possibleMoves)) {
         throw new \LogicException(sprintf('Manipulator:move game:%s, %s can not go to ' . $to . ' (' . implode(',', $possibleMoves) . ')', $this->game->getId(), $piece));
     }
     // killed?
     $killed = $to->getPiece();
     // castling?
     $isCastling = false;
     if ('King' === $pieceClass) {
         // standard castling
         if (1 < abs($from->getX() - $to->getX())) {
             $isCastling = true;
         } elseif ($killed && $killed->getColor() === $piece->getColor()) {
             $isCastling = true;
             $killed = null;
         }
     }
     // promotion?
     if ('Pawn' === $pieceClass && $to->getY() === ($player->isWhite() ? 8 : 1)) {
         $isPromotion = true;
         $promotionClass = isset($options['promotion']) ? ucfirst($options['promotion']) : 'Queen';
         if (!in_array($promotionClass, array('Queen', 'Knight', 'Bishop', 'Rook'))) {
             throw new \InvalidArgumentException(sprintf('Manipulator:move game:%s, Bad promotion class: ' . $promotionClass, $this->game->getId()));
         }
         $options['promotion'] = $promotionClass;
     } else {
         $isPromotion = false;
     }
     // enpassant?
     $isEnPassant = 'Pawn' === $pieceClass && $to->getX() !== $from->getX() && !$killed;
     $pgnDumper = new PgnDumper();
     $pgn = $pgnDumper->dumpMove($this->game, $piece, $from, $to, $playerPossibleMoves, $killed, $isCastling, $isPromotion, $isEnPassant, $options);
     $this->stack->addEvent(array('type' => 'move', 'from' => $from->getKey(), 'to' => $to->getKey(), 'color' => $piece->getColor()));
     if ($isCastling) {
         $this->castle($piece, $to);
     } else {
         if ($killed) {
             $killed->setIsDead(true);
             $this->board->remove($killed);
         }
         $this->board->move($piece, $to->getX(), $to->getY());
         if (null === $piece->getFirstMove()) {
             $piece->setFirstMove($this->game->getTurns());
         }
     }
     if ($isPromotion) {
         $this->promotion($piece, $options['promotion']);
     }
     if ($isEnPassant) {
         $this->enpassant($piece, $to);
     }
     // When an irreversible event happens,
     // we can safely clear the game position hashes
     if ($killed || $isPromotion || $isCastling || 'Pawn' === $pieceClass) {
         $this->game->clearPositionHashes();
     }
     return $pgn;
 }