public void ApplyMove_ShouldIncrementHalfmoveClock_WhenNotAPawnOrCaptureMove() { var fen = "8/8/8/3Q4/8/8/8/8 w - - 0 1"; var moveNotation = "d5e4"; var move = _coordinateNotationParser.ParseNotationMove(moveNotation); var boardState = _fenParser.ParseFen(fen); var moveValidationResult = new MoveValidationResult { IsValid = true, ShouldResetHalfmoveClock = false }; var result = _moveHandler.ApplyMove(boardState, move, moveValidationResult); result.HalfmoveClock.Should().Be(1); }
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); } }