public function compile() { $this->pieces = array(); foreach (PieceFilter::filterAlive($this->getPieces()) as $piece) { $this->pieces[$piece->getSquareKey()] = $piece; } }
/** * @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))); }
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); } } }
protected function getLastPiece(Player $player) { $pieces = PieceFilter::filterNotClass(PieceFilter::filterAlive($player->getPieces()), 'King'); return empty($pieces) ? null : $pieces[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; }
/** * 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; }
/** * 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; }