Example #1
0
        public async Task Move(string moveNotation, string gameId)
        {
            _logger.LogInformation("Move {Move} sent in game {GameId}", moveNotation, gameId);
            await Clients.Caller.SendAsync(GameHubOutgoingMessages.MOVE_RECEIVED);

            var game = _gameRepository.GetGameById(gameId);

            if (game == null)
            {
                return;
            }

            if (!game.Active)
            {
                _logger.LogInformation("Move {Move} was illegal in game {GameId} because game is inactive", moveNotation, gameId);
                await Clients.Caller.SendAsync(GameHubOutgoingMessages.ILLEGAL_MOVE, game.Fen);

                return;
            }

            var userIdString = Context.UserIdentifier;

            if (userIdString == null)
            {
                _logger.LogInformation("Move {Move} was illegal in game {GameId} because user was not logged in", moveNotation, gameId);
                await Clients.Caller.SendAsync(GameHubOutgoingMessages.ILLEGAL_MOVE, game.Fen);

                return;
            }

            var parsedUserId = int.Parse(userIdString);

            if (parsedUserId != game.WhitePlayerId && parsedUserId != game.BlackPlayerId)
            {
                _logger.LogInformation("Move {Move} was illegal in game {GameId} because user {userId} is not a player", moveNotation, gameId, parsedUserId);
                await Clients.Caller.SendAsync(GameHubOutgoingMessages.ILLEGAL_MOVE, game.Fen);

                return;
            }

            var moveValidationResult = _moveValidator.ValidateMove(game.Fen, moveNotation);

            if (!moveValidationResult.IsValid)
            {
                _logger.LogInformation("Move {Move} was illegal in game {GameId}", moveNotation, gameId);
                await Clients.Caller.SendAsync(GameHubOutgoingMessages.ILLEGAL_MOVE, game.Fen);

                return;
            }

            var move = _coordinateNotationParser.ParseNotationMove(moveNotation);
            var currentBoardState = _fenParser.ParseFen(game.Fen);
            var newBoardState     = _moveHandler.ApplyMove(currentBoardState, move, moveValidationResult);

            _gameRepository.AddMoveToGame(gameId, moveNotation, newBoardState.Fen);
            await Clients.Group($"{GAME_GROUP_PREFIX}{gameId}")
            .SendAsync(GameHubOutgoingMessages.MOVE_PLAYED, moveNotation);

            if (moveValidationResult.ShouldResetHalfmoveClock)
            {
                _gameRepository.ClearPositionsFromIrreversibleMove(gameId);
            }

            _gameRepository.AddPositionToGame(gameId, newBoardState.Fen);
            var positionsSinceIrreversibleMove = _gameRepository.GetPositionsSinceIrreversibleMove(gameId);

            if (_moveValidator.IsCheckmate(newBoardState))
            {
                var winner = currentBoardState.ActiveColor;
                await EndGame(game, winner, GameConstants.CHECKMATE_TERMINATION, GameHubOutgoingMessages.CHECKMATE);
            }
            else if (_moveValidator.IsStalemate(newBoardState))
            {
                await EndGame(game, null, GameConstants.STALEMATE_TERMINATION, GameHubOutgoingMessages.DRAW);
            }
            else if (newBoardState.HalfmoveClock >= 100)
            {
                await EndGame(game, null, GameConstants.FIFTY_MOVE_RULE_TERMINATION, GameHubOutgoingMessages.DRAW);
            }
            else if (_moveValidator.IsThreefoldRepetition(newBoardState, positionsSinceIrreversibleMove))
            {
                await EndGame(game, null, GameConstants.THREEFOLD_REPETITION_TERMINATION, GameHubOutgoingMessages.DRAW);
            }
        }