public async Task <GameState> InitGameAsync(InitGameRequest request) { string userId = ExtractUserId(); var player = new Player() { Id = userId, Name = request.UserName, Type = PlayerType.HUMAN }; switch (request.GameType) { case GameType.VS_COMPUTER: { return(InitializeGameVsComputer(player, request)); } case GameType.VS_RANDOM_PLAYER: { return(await InitializeOrJoinGameVsRandomOpponent(player).ConfigureAwait(false)); } case GameType.VS_FRIEND: { return(InitializeGameVsFriend(player)); } default: throw new ArgumentException($"Unsupported game type: ${request.GameType}"); } }
public async Task Test_Quit_Game_Vs_Random_Opponent_Before_Opponent_Joins() { var initRequest = new InitGameRequest { UserName = "******", GameType = GameType.VS_RANDOM_PLAYER }; HubConnection connection = await StartNewConnectionAsync().ConfigureAwait(false); GameState gameState = await connection.InvokeAsync <GameState>(GameHubMethodNames.INIT_GAME, initRequest).ConfigureAwait(false); gameState.Should().NotBeNull(); gameState.BoardState.Should().BeNull(); gameState.Player1.Should().BeEquivalentTo(new Player { Id = ExtractUserId(connection), Name = initRequest.UserName, Type = PlayerType.HUMAN }, "Player 1 must be the one who requested new game"); gameState.Stage.Should().Be(GameStage.WAITING_FOR_OPPONENT); gameState.Player2.Should().Be(null); await connection.InvokeAsync(GameHubMethodNames.QUIT_GAME, new QuitGameRequest { GameId = gameState.Id }).ConfigureAwait(false); }
public GenericResponse InitGame(InitGameRequest request) { try { CellGrid = new CellGrid(request.GridWidth, request.GridHeight); return(GetGenericSuccessfulResponse()); } catch (Exception x) { return(GetFailedGenericResponse(x)); } }
private GameState InitializeGameVsComputer(Player player, InitGameRequest request) { var gameState = new GameState { Id = Guid.NewGuid().ToString("N"), Type = GameType.VS_COMPUTER, StartTimeUtc = DateTime.UtcNow, Stage = GameStage.PLAYING, Player1 = player, Player2 = serverState.ComputerPlayer, BoardState = GameLogicUtils.InitializeGameBoard(request.UserTurn), Difficulty = request.Difficulty ?? serverState.DefaultGameDifficulty }; serverState.AddNewGame(gameState, player); return(gameState); }
private void ButtonSeedGrid_Click(object sender, EventArgs e) { var request = new InitGameRequest() { GridHeight = model.GridHeight, GridWidth = model.GridWidth }; var response = service.InitGame(request); if (response.Successful) { model.GridHasBeenInitialized = true; model.OutputText = response.Output; model.GenerationCount = 0; SetBindingSource(); } else { MessageBox.Show(response.ErrorMessage); } }
public async Task Test_Game_Vs_Random_Opponent_Async() { // Test needs the list of open games on server to be empty to run reliably // TODO: Make this deterministic, one option is use an in-process TestServer #region Game initialization var initRequest = new InitGameRequest { UserName = "******", GameType = GameType.VS_RANDOM_PLAYER }; var joinRequest = new InitGameRequest { UserName = "******", GameType = GameType.VS_RANDOM_PLAYER }; // Request game by player1 HubConnection firstPlayerConnection = await StartNewConnectionAsync().ConfigureAwait(false); GameState initialGameState = await firstPlayerConnection.InvokeAsync <GameState>(GameHubMethodNames.INIT_GAME, initRequest).ConfigureAwait(false); initialGameState.Should().NotBeNull(); initialGameState.BoardState.Should().BeNull(); initialGameState.Player1.Should().BeEquivalentTo(new Player { Id = ExtractUserId(firstPlayerConnection), Name = initRequest.UserName, Type = PlayerType.HUMAN }, "Player 1 must be the one who requested new game"); initialGameState.Stage.Should().Be(GameStage.WAITING_FOR_OPPONENT); initialGameState.Player2.Should().Be(null); bool player1Notified = false; GameState player1NotificationGameState = null; Semaphore player1NotificationSem = new Semaphore(0, 1); // Setup gameStateUpdate message handler for player 1 firstPlayerConnection.On <GameNotification>(GameHubMethodNames.RECEIVE_GAME_STATE_UPDATE, (notification) => { if (!player1Notified) { // First game state update, Just store the state to compare it to state received by player2 player1NotificationGameState = notification.NewGameState; player1Notified = true; player1NotificationSem.Release(); } }); // Request game by player2 HubConnection secondPlayerConnection = await StartNewConnectionAsync().ConfigureAwait(false); secondPlayerConnection.ConnectionId.Should().NotBe(firstPlayerConnection.ConnectionId); // Just to be safe GameState joinedGameState = await secondPlayerConnection.InvokeAsync <GameState>(GameHubMethodNames.INIT_GAME, joinRequest).ConfigureAwait(false); joinedGameState.Id.Should().Be(initialGameState.Id); joinedGameState.Stage.Should().Be(GameStage.PLAYING); joinedGameState.Player2.Should().BeEquivalentTo(new Player { Id = ExtractUserId(secondPlayerConnection), Name = joinRequest.UserName, Type = PlayerType.HUMAN }, "Player 1 must be the one who requested new game"); joinedGameState.BoardState.Should().NotBeNull(); // Wait for notification handler to finish if (player1NotificationSem.WaitOne(80000)) { player1Notified.Should().Be(true); joinedGameState.Should().BeEquivalentTo(player1NotificationGameState); } else { Assert.Fail("Timeout waiting for first player connection to handle notification"); } #endregion #region Gameplay //Let's just play in PUT mode, the goal here is only to test game state update and notification logic not the actual game logic Queue <GameAction> firstMoveSeq = new Queue <GameAction>(); firstMoveSeq.Enqueue(new PutPieceAction { Position = new Point { X = 0, Y = 0 } }); firstMoveSeq.Enqueue(new PutPieceAction { Position = new Point { X = 0, Y = 1 } }); firstMoveSeq.Enqueue(new PutPieceAction { Position = new Point { X = 0, Y = 2 } }); Queue <GameAction> secondMoveSeq = new Queue <GameAction>(); secondMoveSeq.Enqueue(new PutPieceAction { Position = new Point { X = 2, Y = 0 } }); secondMoveSeq.Enqueue(new PutPieceAction { Position = new Point { X = 2, Y = 1 } }); secondMoveSeq.Enqueue(new PutPieceAction { Position = new Point { X = 2, Y = 2 } }); var gameFinishedSem = new Semaphore(0, 1); bool gameOver = false; firstPlayerConnection.On <GameNotification>(GameHubMethodNames.RECEIVE_GAME_STATE_UPDATE, (notification) => { HandleGameStateUpdateNotificationAsync(firstPlayerConnection, notification.NewGameState).Wait(); }); secondPlayerConnection.On <GameNotification>(GameHubMethodNames.RECEIVE_GAME_STATE_UPDATE, (notification) => { HandleGameStateUpdateNotificationAsync(secondPlayerConnection, notification.NewGameState); }); //Play first move HubConnection currentPlayerConnection = joinedGameState.BoardState.CurrentTurn == PlayerTurn.ONE ? firstPlayerConnection : secondPlayerConnection; await HandleGameStateUpdateNotificationAsync(currentPlayerConnection, joinedGameState).ConfigureAwait(false); // Wait for game to finish with timeout gameFinishedSem.WaitOne(TimeSpan.FromSeconds(10)); gameOver.Should().BeTrue("Game must be over"); Task HandleGameStateUpdateNotificationAsync(HubConnection connection, GameState newGameState) { PlayerTurn currentTurn = newGameState.BoardState.CurrentTurn; Queue <GameAction> currentMoveSeq = currentTurn == PlayerTurn.ONE ? firstMoveSeq : secondMoveSeq; HubConnection currentPlayerConnection = currentTurn == PlayerTurn.ONE ? firstPlayerConnection : secondPlayerConnection; currentPlayerConnection.Should().Be(connection, "Connection to handle game state must correspond to the current turn"); Console.WriteLine($"\nReceived game state update, turn number {newGameState.BoardState.TurnNumber}. Board state:\n{ToMatrixString(newGameState.BoardState.Board)}"); if (newGameState.BoardState.Winner != null) { System.Console.WriteLine($"Game Over! Winner is {newGameState.BoardState.Winner}"); gameOver = true; gameFinishedSem.Release(); return(Task.CompletedTask); } else { GameAction nextMove = currentMoveSeq.Dequeue(); System.Console.WriteLine($"Sending game move {nextMove} as player {currentTurn}"); GameActionRequest request = new GameActionRequest { GameId = newGameState.Id, Action = nextMove }; return(currentPlayerConnection.SendAsync(GameHubMethodNames.SEND_GAME_ACTION, request)); } } #endregion }
public async Task Test_Join_Private_Game() { // Doesn't depend on server's state as opposed to the Game_Vs_Random_Opponent test #region Game initialization var initRequest = new InitGameRequest { UserName = "******", GameType = GameType.VS_RANDOM_PLAYER }; // Request game by player1 HubConnection firstPlayerConnection = await StartNewConnectionAsync().ConfigureAwait(false); GameState initialGameState = await firstPlayerConnection.InvokeAsync <GameState>(GameHubMethodNames.INIT_GAME, initRequest).ConfigureAwait(false); initialGameState.Should().NotBeNull(); initialGameState.BoardState.Should().BeNull(); initialGameState.Player1.Should().BeEquivalentTo(new Player { Id = ExtractUserId(firstPlayerConnection), Name = initRequest.UserName, Type = PlayerType.HUMAN }, "Player 1 must be the one who requested new game"); initialGameState.Stage.Should().Be(GameStage.WAITING_FOR_OPPONENT); initialGameState.Player2.Should().Be(null); bool player1Notified = false; GameState player1NotificationGameState = null; Semaphore player1NotificationSem = new Semaphore(0, 1); // Setup gameStateUpdate message handler for player 1 firstPlayerConnection.On <GameNotification>(GameHubMethodNames.RECEIVE_GAME_STATE_UPDATE, (notification) => { if (!player1Notified) { // First game state update, Just store the state to compare it to state received by player2 player1NotificationGameState = notification.NewGameState; player1Notified = true; player1NotificationSem.Release(); } }); // Request game by player2 HubConnection secondPlayerConnection = await StartNewConnectionAsync().ConfigureAwait(false); secondPlayerConnection.ConnectionId.Should().NotBe(firstPlayerConnection.ConnectionId); // Just to be safe var joinRequest = new JoinPrivateGameRequest { GameId = initialGameState.Id, UserName = "******" }; JoinGameResponse response = await secondPlayerConnection.InvokeAsync <JoinGameResponse>(GameHubMethodNames.JOIN_PRIVATE_GAME, joinRequest).ConfigureAwait(false); GameState joinedGameState = response.GameState; response.State.Should().Be(JoinGameResponseType.SUCCESS); joinedGameState.Id.Should().Be(initialGameState.Id); joinedGameState.Stage.Should().Be(GameStage.PLAYING); joinedGameState.Player2.Should().BeEquivalentTo(new Player { Id = ExtractUserId(secondPlayerConnection), Name = joinRequest.UserName, Type = PlayerType.HUMAN }, "Player 1 must be the one who requested new game"); joinedGameState.BoardState.Should().NotBeNull(); // Wait for notification handler to finish if (player1NotificationSem.WaitOne(80000)) { player1Notified.Should().Be(true); joinedGameState.Should().BeEquivalentTo(player1NotificationGameState); } else { Assert.Fail("Timeout waiting for first player connection to handle notification"); } #endregion }
public async Task Test_Opponent_Is_Notified_When_User_Quits_Game(QuitMethod quitMethod) { // TODO: Refactor duplicate code #region Game initialization var initRequest = new InitGameRequest { UserName = "******", GameType = GameType.VS_RANDOM_PLAYER }; var joinRequest = new InitGameRequest { UserName = "******", GameType = GameType.VS_RANDOM_PLAYER }; // Request game by player1 HubConnection firstPlayerConnection = await StartNewConnectionAsync().ConfigureAwait(false); GameState initialGameState = await firstPlayerConnection.InvokeAsync <GameState>(GameHubMethodNames.INIT_GAME, initRequest).ConfigureAwait(false); initialGameState.Should().NotBeNull(); initialGameState.BoardState.Should().BeNull(); initialGameState.Player1.Should().BeEquivalentTo(new Player { Id = ExtractUserId(firstPlayerConnection), Name = initRequest.UserName, Type = PlayerType.HUMAN }, "Player 1 must be the one who requested new game"); initialGameState.Stage.Should().Be(GameStage.WAITING_FOR_OPPONENT); initialGameState.Player2.Should().Be(null); bool player1Notified = false; GameState player1NotificationGameState = null; Semaphore player1NotificationSem = new Semaphore(0, 1); // Setup gameStateUpdate message handler for player 1 firstPlayerConnection.On <GameNotification>(GameHubMethodNames.RECEIVE_GAME_STATE_UPDATE, (gameNotification) => { if (!player1Notified) { // First game state update, Just store the state to compare it to state received by player2 player1NotificationGameState = gameNotification.NewGameState; player1Notified = true; player1NotificationSem.Release(); } }); // Request game by player2 HubConnection secondPlayerConnection = await StartNewConnectionAsync().ConfigureAwait(false); secondPlayerConnection.ConnectionId.Should().NotBe(firstPlayerConnection.ConnectionId); // Just to be safe GameState joinedGameState = await secondPlayerConnection.InvokeAsync <GameState>(GameHubMethodNames.INIT_GAME, joinRequest).ConfigureAwait(false); joinedGameState.Id.Should().Be(initialGameState.Id); joinedGameState.Stage.Should().Be(GameStage.PLAYING); joinedGameState.Player2.Should().BeEquivalentTo(new Player { Id = ExtractUserId(secondPlayerConnection), Name = joinRequest.UserName, Type = PlayerType.HUMAN }, "Player 1 must be the one who requested new game"); joinedGameState.BoardState.Should().NotBeNull(); // Wait for notification handler to finish if (player1NotificationSem.WaitOne(80000)) { player1Notified.Should().Be(true); joinedGameState.Should().BeEquivalentTo(player1NotificationGameState); } else { Assert.Fail("Timeout waiting for first player connection to handle notification"); } #endregion #region Player1 quits game bool quitNotified = false; Semaphore quitNotificationSem = new Semaphore(0, 1); secondPlayerConnection.On(GameHubMethodNames.RECEIVE_OPPONENT_QUIT_NOTIF, () => { quitNotified = true; quitNotificationSem.Release(); }); switch (quitMethod) { case QuitMethod.Message: { await firstPlayerConnection.InvokeAsync(GameHubMethodNames.QUIT_GAME, new QuitGameRequest { GameId = joinedGameState.Id }).ConfigureAwait(false); break; } case QuitMethod.Disconnect: { await firstPlayerConnection.StopAsync().ConfigureAwait(false); break; } default: throw new ArgumentException($"Quitting method '{quitMethod}' not implemented"); } if (quitNotificationSem.WaitOne(10000)) { quitNotified.Should().Be(true, "Player2 must be notified that opponent quit game"); } else { Assert.Fail("Timeout waiting for second player connection to handle opponent quit notification"); } #endregion }
public async Task Test_Game_Vs_Computer_Async() { //TODO: make test deterministic if possible var initRequest = new InitGameRequest { GameType = GameType.VS_COMPUTER, UserName = "******", UserTurn = PlayerTurn.ONE }; // Needed to test playing the game var gameAi = new RandomActionGameAI(); GameDifficulty difficulty = GameDifficulty.MEDIUM; // Totally random int maxActionCount = 5; int actionCount = 0; HubConnection connection = await StartNewConnectionAsync().ConfigureAwait(false); GameState initialGameState = await connection.InvokeAsync <GameState>(GameHubMethodNames.INIT_GAME, initRequest).ConfigureAwait(false); initialGameState.Should().NotBeNull(); initialGameState.BoardState.Should().NotBeNull(); initialGameState.Player1.Should().BeEquivalentTo(new Player { Id = ExtractUserId(connection), Name = initRequest.UserName, Type = PlayerType.HUMAN }, "Player 1 must be the one who requested new game"); initialGameState.Stage.Should().Be(GameStage.PLAYING); initialGameState.Player2.Type.Should().Be(PlayerType.COMPUTER); // Play random moves vs computer GameState currentState = initialGameState; GameState previousState; while (currentState.Stage != GameStage.GAME_OVER && actionCount < maxActionCount) { actionCount++; GameAction nextMove = gameAi.CalculateComputerMove(currentState.BoardState, difficulty); GameActionRequest actionRequest = new GameActionRequest { GameId = initialGameState.Id, Action = nextMove }; Console.WriteLine($"Sending game move on turn {currentState.BoardState.TurnNumber}"); previousState = currentState; var notification = await connection.InvokeAsync <GameNotification>(GameHubMethodNames.SEND_GAME_ACTION, actionRequest).ConfigureAwait(false); currentState = notification.NewGameState; // Check new BoardState if (currentState.Stage != GameStage.GAME_OVER) { currentState.BoardState.TurnNumber.Should().Be(previousState.BoardState.TurnNumber + 2); currentState.BoardState.CurrentTurn.Should().Be(initRequest.UserTurn); System.Console.WriteLine($"Current Board State after computer move:\n{ToMatrixString(currentState.BoardState.Board)}"); } else { System.Console.WriteLine($"Game over, Winner is {currentState.BoardState.Winner} current state:\n{ToMatrixString(currentState.BoardState.Board)}"); } } }