/** * @param MoveInterface $move * * @return string */ public static function toNotation(MoveInterface $move) { if (null === $move->getPiece()) { return ''; } $notation = ''; $piece = $move->getPiece(); $toLabel = strtolower($move->getToLabel()); $isPawn = $piece->getType() === PieceInterface::TYPE_PAWN; $pieceLetter = PieceDecorator::toLetter($piece); if (null !== ($capture = $move->getCapture())) { if ($isPawn) { $column = BoardHelper::getColumnFromPosition($move->getFrom()); $pieceLetter = BoardHelper::columnNumberToLetter($column); } $notation .= sprintf('%sx%s', $pieceLetter, $toLabel); if ($isPawn) { if ($move->getType() === MoveInterface::TYPE_CAPTURE_EN_PASSANT) { $notation .= 'e.p.'; } } return $notation; } if ($isPawn) { return $toLabel; } return sprintf('%s%s', $pieceLetter, $toLabel); }
/** * {@inheritdoc} */ public function configureWalker(BoardWalker $walker, GameInterface $game) { $walker->omnidirectional(1); $kingPosition = BoardHelper::getKingPosition($game->getBoard(), $game->getCurrentColor()); $kingColumn = BoardHelper::getColumnFromPosition($kingPosition); $kingRow = BoardHelper::getRowFromPosition($kingPosition); $board = $game->getBoard(); $king = $board->getSquare($kingPosition)->getPiece(); $track = $kingPosition === SquareInterface::POSITION_E1; // check for possible castle move if (empty($game->getMovesByPiece($king->getId()))) { // see if one of the rooks did not make any moves $rookCriteria = ['piece_type' => PieceInterface::TYPE_ROOK, 'piece_color' => $game->getCurrentColor()]; foreach ($board->getPiecesBy($rookCriteria) as $rookPosition => $rook) { if (empty($game->getMovesByPiece($rook->getId()))) { // see if there are no pieces between the king and this rook $rookColumn = BoardHelper::getColumnFromPosition($rookPosition); $columnDiff = abs($kingColumn - $rookColumn) - 1; $track = $track === true && $columnDiff === 3; if ($columnDiff > 1) { $skip = false; for ($x = 1; $x <= $columnDiff; $x++) { if ($rookColumn > $kingColumn) { $cursor = $rookColumn - $x . $kingRow; } else { $cursor = $rookColumn + $x . $kingRow; } if (null !== ($piece = $board->getSquare($cursor)->getPiece())) { $skip = true; break; } } if ($skip) { continue; } if ($kingColumn > $rookColumn) { if ($game->getCurrentColor() === Color::WHITE) { $walker->jump(BoardWalker::DIRECTION_LEFT, 2); } else { $walker->jump(BoardWalker::DIRECTION_RIGHT, 2); } } else { if ($game->getCurrentColor() === Color::WHITE) { $walker->jump(BoardWalker::DIRECTION_RIGHT, 2); } else { $walker->jump(BoardWalker::DIRECTION_LEFT, 2); } } } } } } }
/** * {@inheritdoc} */ public function getIndexedSquares($indexedBy = 'row') { $squares = []; switch ($indexedBy) { case 'row': $squares = []; foreach ($this->getSquares() as $square) { $row = BoardHelper::getRowFromPosition($square->getPosition()); if (!array_key_exists($row, $squares)) { $squares[$row] = []; } $squares[$row][$square->getPosition()] = $square; } break; case 'column': $squares = []; foreach ($this->getSquares() as $square) { $column = BoardHelper::getColumnFromPosition($square->getPosition()); if (!array_key_exists($column, $squares)) { $squares[$column] = []; } $squares[$column][$square->getPosition()] = $square; } break; } ksort($squares); return $squares; }
/** * @param int $direction The direction to step into * @param int $jumps The number of jumps to make in this direction * @param int|null $startingPosition * @param bool $ignoreCapture * * @return int|null The expected position, or null if the move is not possible * * @throws \InvalidArgumentException */ public function peek($direction, $jumps = 1, $startingPosition = null, $ignoreCapture = false, $requireAttack = false) { $newPosition = null; if ($startingPosition !== null) { $column = BoardHelper::getColumnFromPosition($startingPosition); $row = BoardHelper::getRowFromPosition($startingPosition); } else { $column = $this->getColumn(); $row = $this->getRow(); } switch ($direction) { case self::DIRECTION_FORWARD: if ($this->color === Color::WHITE) { $newRow = $this->formatNumber($row + $jumps); } else { $newRow = $this->formatNumber($row - $jumps); } if ($newRow !== null) { $newPosition = intval($column . $newRow); } break; case self::DIRECTION_FORWARDRIGHT: if ($this->color === Color::WHITE) { $newColumn = $this->formatNumber($column + $jumps); $newRow = $this->formatNumber($row + $jumps); } else { $newColumn = $this->formatNumber($column - $jumps); $newRow = $this->formatNumber($row - $jumps); } if ($newColumn !== null && $newRow !== null) { $newPosition = intval($newColumn . $newRow); } break; case self::DIRECTION_RIGHT: if ($this->color === Color::WHITE) { $newColumn = $this->formatNumber($column + $jumps); } else { $newColumn = $this->formatNumber($column - $jumps); } if ($newColumn !== null) { $newPosition = intval($newColumn . $row); } break; case self::DIRECTION_BACKWARDRIGHT: if ($this->color === Color::WHITE) { $newColumn = $this->formatNumber($column + $jumps); $newRow = $this->formatNumber($row - $jumps); } else { $newColumn = $this->formatNumber($column - $jumps); $newRow = $this->formatNumber($row + $jumps); } if ($newColumn !== null && $newRow !== null) { $newPosition = intval($newColumn . $newRow); } break; case self::DIRECTION_BACKWARD: if ($this->color === Color::WHITE) { $newRow = $this->formatNumber($row - $jumps); } else { $newRow = $this->formatNumber($row + $jumps); } if ($newRow !== null) { $newPosition = intval($column . $newRow); } break; case self::DIRECTION_BACKWARDLEFT: if ($this->color === Color::WHITE) { $newColumn = $this->formatNumber($column - $jumps); $newRow = $this->formatNumber($row - $jumps); } else { $newColumn = $this->formatNumber($column + $jumps); $newRow = $this->formatNumber($row + $jumps); } if ($newColumn !== null && $newRow !== null) { $newPosition = intval($newColumn . $newRow); } break; case self::DIRECTION_LEFT: if ($this->color === Color::WHITE) { $newColumn = $this->formatNumber($column - $jumps); } else { $newColumn = $this->formatNumber($column + $jumps); } if ($newColumn !== null) { $newPosition = intval($newColumn . $row); } break; case self::DIRECTION_FORWARDLEFT: if ($this->color === Color::WHITE) { $newColumn = $this->formatNumber($column - $jumps); $newRow = $this->formatNumber($row + $jumps); } else { $newColumn = $this->formatNumber($column + $jumps); $newRow = $this->formatNumber($row - $jumps); } if ($newColumn !== null && $newRow !== null) { $newPosition = intval($newColumn . $newRow); } break; default: throw new \InvalidArgumentException(sprintf('Unknown direction to calculate: %s', $direction)); } if ($ignoreCapture !== true && $newPosition !== null) { $toPiece = $this->board->getSquare($newPosition)->getPiece(); if (null !== $toPiece) { if ($toPiece->getColor() === $this->getColor()) { // own piece, can't capture return null; } } elseif ($requireAttack === true) { return null; } } return $newPosition; }
/** * @param MoveInterface $move * @param GameInterface $game * * @return int|null */ private static function determineEnPassantType(MoveInterface $move, GameInterface $game) { if (null !== ($lastMove = $game->getLastMove())) { if ($lastMove->getPiece()->getType() === PieceInterface::TYPE_PAWN) { if (abs(BoardHelper::getColumnFromPosition($lastMove->getTo()) - BoardHelper::getColumnFromPosition($move->getFrom())) === 1 && abs(BoardHelper::getRowFromPosition($lastMove->getTo()) - BoardHelper::getRowFromPosition($lastMove->getFrom())) === 2 && BoardHelper::getRowFromPosition($move->getFrom()) === BoardHelper::getRowFromPosition($lastMove->getTo())) { $toPiece = $game->getBoard()->getSquare($move->getTo())->getPiece(); $rowDiff = abs(BoardHelper::getRowFromPosition($move->getFrom()) - BoardHelper::getRowFromPosition($move->getTo())); $columnDiff = abs(BoardHelper::getColumnFromPosition($move->getFrom()) - BoardHelper::getColumnFromPosition($move->getTo())); if ($rowDiff === 1 && $columnDiff === 1) { if ($toPiece === null) { // en passant capture return MoveInterface::TYPE_CAPTURE_EN_PASSANT; } else { return MoveInterface::TYPE_CAPTURE; } } } } } return null; }