예제 #1
0
 protected function createPersistableState(GameInterface $game, GameState $gameState, $class)
 {
     $persistableGameState = $this->createPersistableGameStateObject($class);
     $squares = [];
     foreach ($game->getBoard()->getSquares() as $square) {
         $squareData = ['position' => $square->getPosition(), 'piece' => null];
         if ($piece = $square->getPiece()) {
             $squareData['piece'] = ['id' => $piece->getId(), 'type' => $piece->getType(), 'color' => $piece->getColor()];
         }
         $squares[] = $squareData;
     }
     $persistableGameState->setSquares($squares);
     //$lastMove = $this->createMoveFromGameState($gameState);
     $lastMove = $game->getLastMove();
     if ($lastMove !== null) {
         $persistableGameState->setFrom($lastMove->getFrom());
         $persistableGameState->setTo($lastMove->getTo());
         $persistableGameState->setPiece(['id' => $lastMove->getPiece()->getId(), 'type' => $lastMove->getPiece()->getType(), 'color' => $lastMove->getPiece()->getColor()]);
         if (null !== ($capture = $lastMove->getCapture())) {
             $persistableGameState->setCapture(['captured_id' => $capture->getCapturedPiece()->getId(), 'captured_type' => $capture->getCapturedPiece()->getType(), 'captured_color' => $capture->getCapturedPiece()->getColor(), 'capturing_id' => $capture->getPiece()->getId(), 'capturing_type' => $capture->getPiece()->getType(), 'capturing_color' => $capture->getPiece()->getColor(), 'position' => $capture->getPosition()]);
         }
         $persistableGameState->setMoveType($lastMove->getType());
         $persistableGameState->setColor($lastMove->getPiece()->getColor());
     }
     return $persistableGameState;
 }
예제 #2
0
 /**
  * {@inheritdoc}
  */
 public function save(GameInterface $game)
 {
     $id = $game->getId();
     if ($id === null) {
         $id = $this->generateId();
     }
     $filePath = $this->getPathToFile($id);
     $fh = fopen($filePath, 'w+');
     fwrite($fh, json_encode($game));
     fclose($fh);
 }
예제 #3
0
 /**
  * {@inheritdoc}
  */
 public function configureWalker(BoardWalker $walker, GameInterface $game)
 {
     $pawnMoves = $game->getMovesByPiece($game->getBoard()->getSquare($walker->getStartingPosition())->getPiece()->getId());
     if (empty($pawnMoves)) {
         if ($game->getCurrentColor() === Color::WHITE && $walker->getRow() == 2 || $game->getCurrentColor() === Color::BLACK && $walker->getRow() == 7) {
             $newPosition = $walker->peek(BoardWalker::DIRECTION_FORWARD, 1);
             // allowed to make two steps forward
             if ($newPosition && !$game->getBoard()->getSquare($newPosition)->getPiece()) {
                 $newPosition = $walker->peek(BoardWalker::DIRECTION_FORWARD, 2);
                 if ($newPosition && !$game->getBoard()->getSquare($newPosition)->getPiece()) {
                     // temporary check because walker does not seem to consider obstructing pieces of own color
                     $walker->jump(BoardWalker::DIRECTION_FORWARD, 2)->restart();
                 }
             }
         }
     }
     $walker->forward(1, false)->restart();
     $forwardLeftCapture = $walker->peek(BoardWalker::DIRECTION_FORWARDLEFT, 1, null, false, true);
     $forwardRightCapture = $walker->peek(BoardWalker::DIRECTION_FORWARDRIGHT, 1, null, false, true);
     if ($forwardLeftCapture !== null) {
         $walker->forwardLeft(1)->restart();
     }
     if ($forwardRightCapture !== null) {
         $walker->forwardRight(1)->restart();
     }
     $this->walkEnPassant($walker, $game->getLastMove(false));
 }
예제 #4
0
 /**
  * {@inheritdoc}
  */
 public function save(GameInterface $game)
 {
     if ($game->getId() === null || null === ($persistableGame = $this->loadPersistable($game->getId()))) {
         $persistableGame = $this->createPersistable($game, $this->gameClassName);
         $this->managerRegistry->getManager()->persist($persistableGame);
     }
     $persistableGame->setFinished($game->hasFinished());
     $persistableGame->setFinishedReason($game->getFinishedReason());
     //$persistableGameState = $this->createPersistableState($game, $this->gameStateClassName, $game->getLastMove(true));
     $persistableGameState = $this->createPersistableState($game, $game->getLastState(), $this->gameStateClassName);
     $persistableGame->addState($persistableGameState);
     $this->managerRegistry->getManager()->persist($persistableGameState);
     $this->managerRegistry->getManager()->flush();
     return true;
 }
예제 #5
0
 /**
  * {@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);
                         }
                     }
                 }
             }
         }
     }
 }
예제 #6
0
 /**
  * @param GameInterface $game
  *
  * @return string
  *
  * @todo Add ascii for history, captures, players and clocks
  */
 public static function toAscii(GameInterface $game)
 {
     return BoardDecorator::toAscii($game->getBoard());
 }
예제 #7
0
 /**
  * @param MoveInterface $move
  * @param GameInterface $game
  *
  * @throws InvalidMoveException
  */
 private static function validate(MoveInterface $move, GameInterface $game)
 {
     if ($game->hasFinished()) {
         throw new InvalidMoveException('Game has already finished');
     }
     if (null === ($piece = $move->getPiece())) {
         if (null === ($piece = $game->getBoard()->getSquare($move->getFrom())->getPiece())) {
             var_export($game->getBoard()->getSquaresAsString());
             throw new InvalidMoveException(sprintf('There must be a piece to move on that position: %s', $move->getFromLabel()));
         }
     }
     if ($game->getCurrentColor() !== $piece->getColor()) {
         throw new InvalidMoveException(sprintf('You can only move your own pieces: the %s on %s belongs to %s', $piece->getTypeLabel(), $move->getFromLabel(), $game->getOpposingPlayer()->getColor()));
     }
 }
예제 #8
0
 /**
  * @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();
 }
예제 #9
0
 /**
  * @param GameInterface $game
  *
  * @return array
  */
 private function getExpectedGameArray(GameInterface $game)
 {
     return ['uid' => $game->getId(), 'white_player' => $this->getExpectedPlayerArray($game->getWhitePlayer()), 'black_player' => $this->getExpectedPlayerArray($game->getBlackPlayer()), 'finished' => $game->hasFinished(), 'finished_reason' => $game->getFinishedReason(), 'board' => $this->getExpectedBoardArray($game->getBoard()), 'current_color' => $game->getCurrentColor(), 'states' => $this->getExpectedGameStatesArray($game->getStates()->toArray())];
 }