예제 #1
0
 public function compile()
 {
     $this->pieces = array();
     foreach (PieceFilter::filterAlive($this->getPieces()) as $piece) {
         $this->pieces[$piece->getSquareKey()] = $piece;
     }
 }
예제 #2
0
 /**
  * @depends testGameCreation
  */
 public function testFilterAlive(Entities\Game $game)
 {
     $piece1 = $game->getBoard()->getPieceByPos(1, 1);
     $piece2 = $game->getBoard()->getPieceByPos(2, 1);
     $piece2->setIsDead(true);
     $this->assertSame(array($piece1), PieceFilter::filterAlive(array($piece1, $piece2)));
 }
예제 #3
0
 public function compile()
 {
     $this->pieces = array();
     foreach (PieceFilter::filterAlive($this->getPieces()) as $piece) {
         $this->pieces[$piece->getSquareKey()] = $piece;
     }
     foreach ($this->game->getPlayers() as $player) {
         foreach ($player->getPieces() as $piece) {
             $piece->setBoard($this);
         }
     }
 }
예제 #4
0
 protected function getLastPiece(Player $player)
 {
     $pieces = PieceFilter::filterNotClass(PieceFilter::filterAlive($player->getPieces()), 'King');
     return empty($pieces) ? null : $pieces[0];
 }
예제 #5
0
 /**
  * Transform a game to standard Forsyth Edwards Notation
  * http://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation
  */
 public static function export(Game $game, $positionOnly = false)
 {
     static $reverseClasses = array('Pawn' => 'p', 'Rook' => 'r', 'Knight' => 'n', 'Bishop' => 'b', 'Queen' => 'q', 'King' => 'k');
     $board = $game->getBoard();
     $emptySquare = 0;
     $forsyth = '';
     for ($y = 8; $y > 0; $y--) {
         for ($x = 1; $x < 9; $x++) {
             if ($piece = $board->getPieceByPosNoCheck($x, $y)) {
                 if ($emptySquare) {
                     $forsyth .= $emptySquare;
                     $emptySquare = 0;
                 }
                 $notation = $reverseClasses[$piece->getClass()];
                 if ('white' === $piece->getColor()) {
                     $notation = strtoupper($notation);
                 }
                 $forsyth .= $notation;
             } else {
                 ++$emptySquare;
             }
         }
         if ($emptySquare) {
             $forsyth .= $emptySquare;
             $emptySquare = 0;
         }
         $forsyth .= '/';
     }
     $forsyth = trim($forsyth, '/');
     if ($positionOnly) {
         return $forsyth;
     }
     // b ou w to indicate turn
     $forsyth .= ' ';
     $forsyth .= substr($game->getTurnColor(), 0, 1);
     // possibles castles
     $forsyth .= ' ';
     $hasCastle = false;
     $analyser = new Analyser($board);
     foreach ($game->getPlayers() as $player) {
         if ($analyser->canCastleKingSide($player)) {
             $hasCastle = true;
             $forsyth .= $player->isWhite() ? 'K' : 'k';
         }
         if ($analyser->canCastleQueenSide($player)) {
             $hasCastle = true;
             $forsyth .= $player->isWhite() ? 'Q' : 'q';
         }
     }
     if (!$hasCastle) {
         $forsyth .= '-';
     }
     // en passant
     $enPassant = '-';
     foreach (PieceFilter::filterClass(PieceFilter::filterAlive($game->getPieces()), 'Pawn') as $piece) {
         if ($piece->getFirstMove() === $game->getTurns() - 1) {
             $color = $piece->getPlayer()->getColor();
             $y = $piece->getY();
             if ($color === 'white' && 4 === $y || $color === 'black' && 5 === $y) {
                 $enPassant = Board::posToKey($piece->getX(), 'white' === $color ? $y - 1 : $y + 1);
                 break;
             }
         }
     }
     $forsyth .= ' ' . $enPassant;
     // Halfmove clock: This is the number of halfmoves since the last pawn advance or capture.
     // This is used to determine if a draw can be claimed under the fifty-move rule.
     $forsyth .= ' ' . $game->getHalfmoveClock();
     // Fullmove number: The number of the full move. It starts at 1, and is incremented after Black's move.
     $forsyth .= ' ' . $game->getFullMoveNumber();
     return $forsyth;
 }
예제 #6
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;
 }
예제 #7
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();
         $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;
 }