/// <inheritdoc /> public GameMoveDetails GetMove(string gameId, int moveNumber) { if (string.IsNullOrWhiteSpace(gameId)) { throw new ArgumentException(nameof(gameId)); } if (moveNumber < 0) { throw new ArgumentOutOfRangeException(nameof(moveNumber)); } var game = GetById(gameId); if (game == null) { return(null); } LoadGameBoard(game); var move = game.GameBoard.Moves.ElementAtOrDefault(moveNumber); if (move == null) { return(null); } return(GameMoveDetails.FromEntity(game, move)); }
public virtual IActionResult PlayMove([FromRoute][Required] string gameId, [FromRoute][Required] string playerName, [FromBody][Required] int column) { try { var gameMove = new GameMoveDetails() { Player = playerName, Column = column, Type = GameMove.MoveType.MOVE }; var move = _gameService.PlayMove(gameId, gameMove); if (move == null) { return(NotFound()); } return(CreatedAtAction(nameof(GetMove), new { gameId, moveNumber = move.MoveId }, move)); } catch (PlayerTurnException) { return(Conflict()); } catch (PlayerNotFoundException) { return(NotFound()); } // InvalidOperationException means the play was invalid catch (InvalidOperationException) { return(BadRequest()); } }
/// <inheritdoc /> public GameMove PlayMove(string gameId, GameMoveDetails newMove) { if (string.IsNullOrWhiteSpace(gameId)) { throw new ArgumentException(nameof(gameId)); } if (newMove == null) { throw new ArgumentNullException(nameof(newMove)); } var game = GetById(gameId); if (game == null) { return(null); } if (GetActivePlayer(game).Name != newMove.Player) { throw new PlayerTurnException($"It is not {newMove.Player}'s turn"); } if (GetGameState(game) == Game.GameState.DONE) { throw new InvalidOperationException($"Game is finished! Cannot play new moves."); } var player = game.Players.SingleOrDefault(p => p.Name == newMove.Player); if (player == null) { throw new PlayerNotFoundException($"{newMove.Player} does not exist in game {gameId}"); } if (!game.GameBoard.DropToken(newMove.Column, player.Id)) { throw new InvalidOperationException($"Could not place token in column {newMove.Column}; column is full"); } var move = new GameMove() { Column = newMove.Column, PlayerId = player.Id, MoveId = game.GameBoard.Moves.Count() + 1, // TODO: This smells inefficient - is there a better way than re-counting? Check the generated SQL. Type = newMove.Type }; game.GameBoard.Moves.Add(move); game.State = GetGameState(game); Context.SaveChanges(); // TODO: Leaky abstraction; move to data layer? return(move); }
/// <inheritdoc /> public IEnumerable <GameMoveDetails> GetMoves(string gameId) { if (string.IsNullOrWhiteSpace(gameId)) { throw new ArgumentException(nameof(gameId)); } var game = GetById(gameId); if (game == null) { return(null); } LoadGameBoard(game); return(game.GameBoard.Moves.Select(move => GameMoveDetails.FromEntity(game, move))); }
/// <inheritdoc /> public IEnumerable <GameMoveDetails> GetMoves(string gameId, int start, int until) { if (string.IsNullOrWhiteSpace(gameId)) { throw new ArgumentException(nameof(gameId)); } if (start < 0) { throw new ArgumentOutOfRangeException(nameof(start)); } if (until < 0) { throw new ArgumentOutOfRangeException(nameof(until)); } if (until < start) { throw new ArgumentException("until cannot be less than start"); } var game = GetById(gameId); if (game == null) { return(null); } LoadGameBoard(game); // TODO: This could be more efficient by only returning the desired rows from the database // instead of loading them all into memory, then converting to array, then segmenting it var moves = new ArraySegment <GameMove>(game.GameBoard.Moves.ToArray(), start, until - start + 1); return(moves.Select(move => GameMoveDetails.FromEntity(game, move))); }