/** * @param BoardWalker $walker * @param MoveInterface $lastMove */ private function walkEnPassant(BoardWalker $walker, MoveInterface $lastMove = null) { $lastEnemyPiece = $lastMove ? $walker->getBoard()->getSquare($lastMove->getTo())->getPiece() : null; if ($lastMove === null || $lastEnemyPiece === null || $lastEnemyPiece->getType() !== PieceInterface::TYPE_PAWN) { return; } $leftToPosition = $walker->peek(BoardWalker::DIRECTION_LEFT, 1, null, true, false); $rightToPosition = $walker->peek(BoardWalker::DIRECTION_RIGHT, 1, null, true, false); if ($leftToPosition !== null) { if (abs(BoardHelper::getRowFromPosition($lastMove->getFrom()) - BoardHelper::getRowFromPosition($leftToPosition)) !== 2) { return; } if ($lastMove->getTo() === $leftToPosition) { // en passant left $walker->forwardLeft(1, false)->restart(); } } if ($rightToPosition !== null) { if (abs(BoardHelper::getRowFromPosition($lastMove->getFrom()) - BoardHelper::getRowFromPosition($rightToPosition)) !== 2) { return; } if ($lastMove->getTo() === $rightToPosition) { // en passant left $walker->forwardRight(1, false)->restart(); } } }
/** * {@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; }