/** * @param string $notation * @param GameInterface $game * @param array $parsed * * @return int * * @throws InvalidNotationException */ private function parseFrom($notation, GameInterface $game, array $parsed) { $enPassant = false; $capture = false; switch ($parsed['piece_type']) { case PieceInterface::TYPE_PAWN: if (substr($notation, -4) === 'e.p.') { $enPassant = true; } elseif (substr($notation, 1, 1) === 'x') { // calculate 'from' for capture by pawn (diagonally) $capture = true; } else { // calculate 'from' for forward move by pawn } break; default: // non-pawn calculation, depends on type break; } $finalMove = null; $criteria = ['piece_color' => $parsed['color'], 'piece_type' => $parsed['piece_type']]; if (strlen($notation) > 3 && in_array(substr($notation, 1, 1), ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])) { $criteria['column'] = BoardHelper::columnLetterToNumber(substr($notation, 1, 1)); } $possiblePieceMoves = $this->moveCalculator->possibleMovesTo($parsed['to'], $game->getBoard(), $criteria); foreach ($possiblePieceMoves as $move) { MoveHelper::enrich($move, $game); if ($enPassant === true && $move->getType() !== MoveInterface::TYPE_CAPTURE_EN_PASSANT) { continue; } elseif ($capture === true && $move->getType() !== MoveInterface::TYPE_CAPTURE) { continue; } if ($finalMove !== null) { throw new InvalidNotationException(sprintf('Multiple moves found starting from %s and ending on %s, you should make your notation more specific (criteria: %s)', $finalMove->getFromLabel(), $finalMove->getToLabel(), json_encode($criteria))); } $finalMove = $move; } if ($finalMove === null) { throw new InvalidNotationException(sprintf('There are no moves to make to this position: %s (criteria: %s)', $parsed['to'], json_encode($criteria, true))); } return $finalMove->getFrom(); }
/** * @param int $colorToMove * @param Board $board * * @return array */ private function getSimplifiedActualMoves($colorToMove, Board $board) { $moves = []; $moveCalculator = new MoveCalculator(); foreach ($moveCalculator->possibleMovesBy($colorToMove, $board) as $actualMove) { $moves[] = [$actualMove->getFrom(), $actualMove->getTo()]; } return $moves; }
/** * {@inheritdoc} */ public function doEngineMove(MoveCalculator $moveCalculator) { $currentPlayer = $this->getCurrentPlayer(); if ($currentPlayer->isHuman()) { throw new \LogicException('Can\\t make an engine-move with a human player'); } $possibleMoves = $moveCalculator->possibleMovesBy($currentPlayer->getColor(), $this->getBoard()); if (empty($possibleMoves)) { throw new \RuntimeException('Failed to find a move for the engine... probably because this scenario wasn\'t worked out yet'); } $highestRankingMove = MoveRanker::best($possibleMoves, $this, $moveCalculator); MoveHelper::apply($highestRankingMove, $this); $this->addState($this->createStateFromMove($highestRankingMove)); return $highestRankingMove; }