示例#1
0
        public async Task LogAction()
        {
            // Arrange
            var logActionRequest = new GameActionRequest()
            {
                GameId    = 1,
                TeamId    = 1,
                Latitude  = 45.26,
                Longitude = 4.63,
                Action    = (int)Action.StartGame.GetTypeCode()
            };

            var httpResponse = new HttpResponseMessage()
            {
                Content = new StringContent("OK")
            };

            A.CallTo(_fakeHttpMessageHandler)
            .Where(x => x.Method.Name == "PostAsync")
            .WithReturnType <Task <HttpResponseMessage> >()
            .Returns(httpResponse);
            // Act
            await _target.LogAction(logActionRequest);

            // Assert
            A.CallTo(_fakeHttpMessageHandler)
            .Where(x => x.Method.Name == "SendAsync")
            .WithReturnType <Task <HttpResponseMessage> >().MustHaveHappened();
        }
示例#2
0
        static async Task InsertRandomPosition(int gameId, int minTeamId, int maxTeamId, double latitude, double longitude, int interval = 15000)
        {
            var random            = new Random((int)DateTime.Now.Ticks);
            var gameActionRequest = new GameActionRequest()
            {
                GameId    = gameId,
                Latitude  = latitude,
                Longitude = longitude,
            };

            do
            {
                gameActionRequest.Action     = random.Next(0, 7);
                gameActionRequest.TeamId     = random.Next(minTeamId, maxTeamId + 1);
                gameActionRequest.TeamId     = random.Next(minTeamId, maxTeamId + 1);
                gameActionRequest.Latitude  += 0.001 * (random.NextDouble() - 0.5);
                gameActionRequest.Longitude += 0.001 * (random.NextDouble() - 0.5);
                try
                {
                    await _actionWebService.LogAction(gameActionRequest);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }

                Thread.Sleep(interval);
            } while (true);
        }
示例#3
0
        public void AddGameAction_ReplyQuestion()
        {
            // Arrange
            var gameActionRequest = new GameActionRequest()
            {
                Action    = 4,
                Latitude  = 1.2,
                Longitude = 50.2,
                NodeId    = 2,
                GameId    = 2,
                TeamId    = 5,
                AnswerId  = 3
            };
            var questionNode = new QuestionNode()
            {
                Answers = new List <Answer>()
                {
                    new Answer(), new Answer()
                    {
                        Correct = true
                    }, new Answer()
                }
            };

            A.CallTo(() => _nodeService.GetNode(A <int> ._)).Returns(questionNode);
            // Act
            var result = _target.AddGameAction(gameActionRequest);

            // Assert
            A.CallTo(() => _nodeService.GetAnswer(A <int> ._)).MustHaveHappened();
            A.CallTo(() => _nodeService.GetNode(gameActionRequest.NodeId)).MustHaveHappened();
            A.CallTo(() => _actionService.AddGameAction(A <GameAction> .That.Matches(ga => CheckGameActionWithAnswer(ga))))
            .MustHaveHappened();
        }
示例#4
0
        public override async Task Begin(ITurnContext turnContext)
        {
            var state = turnContext.GetConversationState <ImageHuntState>();

            if (state.Status != Status.Initialized)
            {
                LogInfo <ImageHuntState>(turnContext, "Game not initialized");
                await turnContext.ReplyActivity("Le chat n'a pas été initialisé, impossible de commencer maintenant!");

                await turnContext.End();

                return;
            }
            LogInfo <ImageHuntState>(turnContext, "Start Game");

            var gameActionRequest = new GameActionRequest()
            {
                Action    = (int)ImageHuntWebServiceClient.Action.StartGame,
                GameId    = state.GameId,
                TeamId    = state.TeamId,
                Latitude  = state.CurrentLatitude,
                Longitude = state.CurrentLongitude
            };

            state.Status = Status.Started;
            await _actionWebService.LogAction(gameActionRequest);

            await turnContext.ReplyActivity($"La chasse commence maintenant! Bonne chance!");

            await turnContext.End();
        }
示例#5
0
        public override async Task Begin(ITurnContext turnContext)
        {
            var state = turnContext.GetConversationState <ImageHuntState>();

            if (state.Status != Status.Started)
            {
                LogInfo <ImageHuntState>(turnContext, "The game had not started!");
                await turnContext.ReplyActivity("La partie n'a pas encore commencée, vous ne pouvez par l'arrêter!");

                await turnContext.End();
            }
            _logger.LogInformation($"The Hunt of GameId={state.GameId} for teamid={state.TeamId} had ended.");
            var gameActionRequest = new GameActionRequest()
            {
                Action    = (int)ImageHuntWebServiceClient.Action.EndGame,
                GameId    = state.GameId,
                TeamId    = state.TeamId,
                Latitude  = state.CurrentLatitude,
                Longitude = state.CurrentLongitude
            };

            state.Status = Status.Ended;
            await _actionWebService.LogAction(gameActionRequest);

            await turnContext.ReplyActivity(
                $"La chasse vient de prendre fin, vos actions ont été enregistrée et un orga va les valider.");

            await turnContext.End();
        }
示例#6
0
        public override async Task OnGameActionRequested(GameActionRequest actionRequest)
        {
            // OnGameActionRequested fires when your bot actually needs to do something. In the request, you will find the entire game
            // state (what you would normally see on the game table) and a list of possible actions. Some actions have options that
            // you need to provide when taking them, things like how many dice to roll, or which building you would like to buy.
            string log   = "OnGameActionRequested - Possible Actions:";
            bool   first = true;

            foreach (GameActionType type in actionRequest.PossibleActions)
            {
                if (!first)
                {
                    log += ",";
                }
                first = false;
                log  += $" {type.ToString()}";
            }
            Logger.Log(Log.Info, log);

            // This state helper object is super useful object that helps you understand the current state of the game.
            // There are 4 modules to the state helper. Each helper has functions specific the to topic.
            //     Player
            //         ex. GetPlayer(), GetNumberOfLandmarksOwned(), GetMaxRollsAllowed(), CanHaveExtraTurn()
            //     Marketplace
            //         ex. GetMaxBuildingsInGame(), GetBuiltBuildingsInCurrentGame(), GetBuildingTypesBuildableInMarketplace()
            //     CurrentTurn
            //         ex. CanRollOrReRoll(), GetPossibleActions(), CanTakeAction()
            //     BuildingRules
            //         This helper holds all of the building types and the rules of them. ex. BuildingRules[buildingIndex].GetColor()
            //
            StateHelper stateHelper = actionRequest.State.GetStateHelper(GetCurrentUserName());

            // Ask the log core to handle the action request.
            await m_logicCore.OnGameActionRequested(actionRequest, stateHelper);
        }
示例#7
0
 public async Task LogAction(GameActionRequest logActionRequest,
                             CancellationToken cancellationToken = default(CancellationToken))
 {
     using (var content = new MultipartFormDataContent())
     {
         content.Add(new StringContent(logActionRequest.GameId.ToString()), "gameId");
         content.Add(new StringContent(logActionRequest.TeamId.ToString()), "teamId");
         content.Add(new StringContent(logActionRequest.Latitude.ToString()), "latitude");
         content.Add(new StringContent(logActionRequest.Longitude.ToString()), "longitude");
         content.Add(new StringContent(logActionRequest.Action.ToString()), "action");
         var result = await PostAsync <string>($"{_httpClient.BaseAddress}api/Action/AddGameAction/",
                                               content, cancellationToken);
     }
 }
示例#8
0
        public async Task <GameNotification> SendGameActionAsync(GameActionRequest actionRequest)
        {
            GameState gameState = serverState.GetGameState(actionRequest.GameId);

            if (!gameLogic.ValidateGameAction(actionRequest, gameState))
            {
                // TODO: make error messages clearer
                throw new ArgumentException("Invalid move");
            }
            GameState newState = gameLogic.ApplyAction(gameState, actionRequest.Action);

            Player player = GameLogicUtils.GetCurrentPlayer(newState);

            if (player.Type == PlayerType.COMPUTER)
            {
                if (newState.Stage == GameStage.GAME_OVER)
                {
                    return(new GameNotification {
                        NewGameState = newState
                    });
                }
                // Get computer's move and return new state to player
                GameAction computerAction    = gameAI.CalculateComputerMove(newState.BoardState, newState.Difficulty);
                GameState  afterComputerMove = gameLogic.ApplyAction(newState, computerAction);

                serverState.UpdateGameState(afterComputerMove);
                return(new GameNotification {
                    LastAction = computerAction,
                    NewGameState = afterComputerMove
                });
            }
            else
            {
                serverState.UpdateGameState(newState);
                // Notify opponent
                var notification = new GameNotification
                {
                    NewGameState = newState,
                    LastAction   = actionRequest.Action
                };
                await Clients.Client(player.Id).ReceiveGameStateUpdate(notification).ConfigureAwait(false);

                return(notification);
            }
        }
示例#9
0
        public async Task <IActionResult> AddGameAction(GameActionRequest gameActionRequest)
        {
            var gameAction = Mapper.Map <GameAction>(gameActionRequest);

            gameAction.Team      = _teamService.GetTeamById(gameActionRequest.TeamId);
            gameAction.Game      = _gameService.GetGameById(gameActionRequest.GameId);
            gameAction.Latitude  = gameActionRequest.Latitude;
            gameAction.Longitude = gameActionRequest.Longitude;
            gameAction.Action    = (Action)gameActionRequest.Action;
            if (gameActionRequest.NodeId != 0)
            {
                gameAction.Node = _nodeService.GetNode(gameActionRequest.NodeId);
            }
            gameAction.DateOccured = DateTime.Now;

            switch (gameAction.Action)
            {
            case Action.DoAction:
            case Action.SubmitPicture:
                if (string.IsNullOrEmpty(gameActionRequest.Picture))
                {
                    _logger.LogError("The picture Base64 string is empty, action is ignored");
                    return(BadRequest(gameActionRequest));
                }
                var picture = new Picture();
                var bytes   = Convert.FromBase64String(gameActionRequest.Picture);
                picture.Image = bytes;
                _imageService.AddPicture(picture);
                gameAction.Picture = picture;
                break;

            case Action.ReplyQuestion:
                var answer = _nodeService.GetAnswer(gameActionRequest.AnswerId);
                gameAction.SelectedAnswer = answer;
                var correctAnswer = ((QuestionNode)gameAction.Node).Answers.Single(a => a.Correct);
                gameAction.CorrectAnswer = correctAnswer;
                break;
            }
            _actionService.AddGameAction(gameAction);
            await NotifyClientsForGameAction(gameAction);

            return(CreatedAtAction("AddGameAction", gameAction));
        }
示例#10
0
        public async Task AddGameAction_StartGame()
        {
            // Arrange
            var gameActionRequest = new GameActionRequest()
            {
                Action    = 0,
                Latitude  = 1.2,
                Longitude = 50.2,
                GameId    = 2,
                TeamId    = 5
            };
            // Act
            var result = await _target.AddGameAction(gameActionRequest);

            // Assert
            Check.That(result).IsInstanceOf <CreatedAtActionResult>();
            A.CallTo(() => _actionService.AddGameAction(A <GameAction> .That.Matches(ga => CheckGameActionForAction(ga, Action.StartGame, gameActionRequest.Latitude, gameActionRequest.Longitude))))
            .MustHaveHappened();
        }
        public IActionResult Put(int id, [FromBody] GameActionRequest gameUpdateRequest)
        {
            Player player = (Player)HttpContext.Items["Player"];

            Race race = raceRepo.Find(gameUpdateRequest.gameId);

            if (race == null)
            {
                return(new NotFoundResult());
            }

            GameActionRequest.ActionType type = gameUpdateRequest.type;

            if (type == GameActionRequest.ActionType.FORFEIT)
            {
                bool result = race.Remove(player);
                if (result == true)
                {
                    player.nrOfDroppedGames++; // Bad for reputation.
                    return(new OkResult());
                }
                return(new BadRequestResult());
            }
            else if (type == GameActionRequest.ActionType.MOVE)
            {
                int newX = gameUpdateRequest.x;
                int newY = gameUpdateRequest.y;
                // Check if user are allowed to make move.
                bool allowed = race.UpdatePlayer(player, newX, newY);
                if (allowed != true)
                {
                    return(new BadRequestResult());
                }
            }
            else
            {
                return(new BadRequestResult());
            }
            return(new OkResult());
        }
示例#12
0
        public async Task AddGameAction_UploadPicture()
        {
            // Arrange
            var gameActionRequest = new GameActionRequest()
            {
                Action    = 2,
                Latitude  = 1.2,
                Longitude = 50.2,
                Picture   = "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",
                GameId    = 2,
                TeamId    = 5
            };
            // Act
            var result = await _target.AddGameAction(gameActionRequest);

            // Assert
            Check.That(result).IsInstanceOf <CreatedAtActionResult>();
            A.CallTo(() => _teamService.GetTeamById(gameActionRequest.TeamId)).MustHaveHappened();
            A.CallTo(() => _gameService.GetGameById(gameActionRequest.GameId)).MustHaveHappened();
            A.CallTo(() => _imageService.AddPicture(A <Picture> .That.Matches(p => CheckPicture(p)))).MustHaveHappened();
            A.CallTo(() => _actionService.AddGameAction(A <GameAction> .That.Matches(ga => CheckGameActionForImage(ga, gameActionRequest.Latitude, gameActionRequest.Longitude)))).MustHaveHappened();
            A.CallTo(() => _nodeService.GetNode(A <int> ._)).MustNotHaveHappened();
        }
示例#13
0
        public override async Task OnGameActionRequested(GameActionRequest actionRequest)
        {
            // OnGameActionRequested fires when your bot actually needs to do something. In the request, you will find the entire game state (what you would normally see on the table)
            // and a list of possible actions. Some actions have options that you need to provide when taking them, things like how many dice to roll, or which building you would like to buy.
            string log   = "OnGameActionRequested - Possible Actions:";
            bool   first = true;

            foreach (GameActionType type in actionRequest.PossibleActions)
            {
                if (!first)
                {
                    log += ",";
                }
                first = false;
                log  += $" {type.ToString()}";
            }
            Logger.Log(Log.Info, log);

            // This state helper object is useful to validate state questions.
            StateHelper stateHelper = actionRequest.State.GetStateHelper(GetCurrentUserName());

            // Ask the log core to handle the action request.
            await m_logicCore.OnGameActionRequested(actionRequest, stateHelper);
        }
示例#14
0
 public async Task <ActionResult <MinesweeperApi.Models.Minesweeper> > PostGame(string gameID, GameActionRequest action)
 {
示例#15
0
 public bool ValidateGameAction([DisallowNull] GameActionRequest actionRequest, [DisallowNull] GameState state)
 {
     // We have client side validation now
     // TODO: Implement it correctly
     return(true);
 }
示例#16
0
 // Fires when the game the bot has connected wants the bot to decide on an action.
 // This will fire as part of the bot's turn, the argument object has details on the actions that can be preformed.
 public abstract Task OnGameActionRequested(GameActionRequest actionRequest);
示例#17
0
        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)}");
                }
            }
        }
        public async Task OnGameActionRequested(GameActionRequest actionRequest, StateHelper stateHelper)
        {
            // Always roll if it's an option.
            if (actionRequest.PossibleActions.Contains(GameActionType.RollDice))
            {
                // If we can roll the dice.... LET'S DO IT!

                // Always roll ALL THE DICE
                int maxDiceCount = stateHelper.Player.GetMaxCountOfDiceCanRoll();

                // Check if we have another roll.
                int  rollsSoFar = stateHelper.GetState().CurrentTurnState.Rolls;
                bool canReRoll  = stateHelper.Player.GetMaxRollsAllowed() < rollsSoFar;

                // If we can't reroll, auto commit the dice. Otherwise don't, so we can reroll if we want.
                Logger.Log(Log.Info, "Requesting a dice roll! BIG MONEY NO WHAMMIES...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateRollDiceAction(maxDiceCount, !canReRoll));

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to roll dice.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, "Trust the dice gods, we roll the dice and commit!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.BuildBuilding))
            {
                // WE ARE A BIG ROLLER... let's build.

                // Get all building that are in the marketplace currently.
                List <int> buildable = stateHelper.Marketplace.GetBuildingTypesBuildableInMarketplace();

                // Filter it down to only buildings we can afford.
                List <int> affordable = stateHelper.Player.FilterBuildingIndexesWeCanAfford(buildable);

                // Randomly pick one.
                int buildingIndex = affordable[m_random.RandomInt(0, affordable.Count - 1)];

                // IF WE BUILD IT...
                Logger.Log(Log.Info, $"Requesting to build {stateHelper.BuildingRules[buildingIndex].GetName()}...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateBuildBuildingAction(buildingIndex));

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to build building.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We just bought {stateHelper.BuildingRules[buildingIndex].GetName()}!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.EndTurn))
            {
                // If we can't roll the dice or build a building, we must not have enough funds.
                // Just end the turn.

                // End it!
                Logger.Log(Log.Info, "There's nothing to do, requesting turn end...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateEndTurnAction());

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to end our turn.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We have {stateHelper.Player.GetPlayer().Coins} coins and can't buy anything, so we ended the turn.");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.TvStationPayout))
            {
                // Our Tv Station activated! Let's take 5 coins from a player at random.
                GamePlayer randomPlayer = GetRandomPlayer(stateHelper);

                // DO IT!!!
                Logger.Log(Log.Info, $"Our Tv Station was activated, let's take coins from player {randomPlayer.Name}!");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateTvStationPayoutAction(randomPlayer.PlayerIndex));

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to respond to tv station payout.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We taken coins from player {randomPlayer.Name} for our tv station!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.BusinessCenterSwap))
            {
                // Our Business Center activated! Let's randomly pick a player and building to swap.
                GamePlayer   randomPlayer  = GetRandomPlayer(stateHelper);
                BuildingBase ourBuilding   = GetRandomOwnedNonMajorBuidling(stateHelper, null);
                BuildingBase theirBuilding = GetRandomOwnedNonMajorBuidling(stateHelper, randomPlayer.PlayerIndex);

                GameActionResponse result;
                if (randomPlayer == null || ourBuilding == null || theirBuilding == null)
                {
                    // If there aren't any building we can use, skip the action.
                    Logger.Log(Log.Info, $"Our Business Center was activated, but there weren't the correct building to swap. So we will skip!");
                    result = await m_bot.SendAction(GameAction <object> .CreateBusinessCenterSwapAction(0, 0, 0, true));
                }
                else
                {
                    Logger.Log(Log.Info, $"Our Business Center was activated, swap our {ourBuilding.GetName()} for {randomPlayer.Name}'s {theirBuilding.GetName()}!");
                    result = await m_bot.SendAction(GameAction <object> .CreateBusinessCenterSwapAction(randomPlayer.PlayerIndex, ourBuilding.GetBuildingIndex(), theirBuilding.GetBuildingIndex()));
                }

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to respond to business center swap.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"Business center swap done!");
                }
                return;
            }

            Logger.Log(Log.Error, $"Hmm, we were asked for an action but didn't know what to do with...");
            foreach (GameActionType type in actionRequest.PossibleActions)
            {
                Logger.Log(Log.Error, $"  ... {type.ToString()}");
                await Shutdown("received an unknown action.", null);
            }
        }
        public async Task OnGameActionRequested(GameActionRequest actionRequest, StateHelper stateHelper)
        {
            // OnGameActionRequested is called when the bot actually needs to take an action. Below is an example of how this can
            // be done and what events your bot will need to handle.
            //
            // To see all of the actions your must handle, look at GameActionType.
            //
            // actionRequest.State is the root of the state object for the game. This holds all things like players, coin amounts,
            // what building are in the marketplace, states of the current turn, etc.
            // Essentially, this object is everything you would see on the table when playing the game.
            //
            // The statehelper is a very useful tool that will answer many current state questions. The state helper takes a perspective user
            // when it's created, that it will use as a default player if no player is given.
            // For example, the Player.GetPlayerName function takes an option playerIndex. If not given, it will return your name.
            //
            // There are 4 modules to the state helper. Each helper has functions specific the to topic.
            //     Player
            //         ex. GetPlayer(), GetNumberOfLandmarksOwned(), GetMaxRollsAllowed(), CanHaveExtraTurn()
            //     Marketplace
            //         ex. GetMaxBuildingsInGame(), GetBuiltBuildingsInCurrentGame(), GetBuildingTypesBuildableInMarketplace()
            //     CurrentTurn
            //         ex. CanRollOrReRoll(), GetPossibleActions(), CanTakeAction()
            //     BuildingRules
            //         This helper holds all of the building types and the rules of them. ex. BuildingRules[buildingIndex].GetColor()
            //

            // Always roll if it's an option.
            if (actionRequest.PossibleActions.Contains(GameActionType.RollDice))
            {
                // How many dice can we roll?
                int maxDiceCount = stateHelper.Player.GetMaxCountOfDiceCanRoll();

                // Can we re-roll
                int  rollsSoFar = stateHelper.GetState().CurrentTurnState.Rolls;
                bool canReRoll  = stateHelper.Player.GetMaxRollsAllowed() < rollsSoFar;

                // If we can't reroll, auto commit the dice. Otherwise don't, so we can reroll if we want.
                Logger.Log(Log.Info, "Rolling the dice!");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateRollDiceAction(maxDiceCount, !canReRoll));

                if (!result.Accepted)
                {
                    await Shutdown("failed to roll dice.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, "Done");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.CommitDiceResult))
            {
                // This action is used if you want to see the dice results before they are committed.
                // It's useful to see the results if you have the ability to re-roll, so you can decided to re-roll.
                // But if the `autoCommitResults` flag is set to true when you call `CreateRollDiceAction` this wont' get called,
                // because the server will always do this for you.

                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateCommitDiceResultAction());

                if (!result.Accepted)
                {
                    await Shutdown("failed to commit dice.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, "Done");
                }
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.BuildBuilding))
            {
                // Get all building that are in the marketplace currently.
                List <int> buildable = stateHelper.Marketplace.GetBuildingTypesBuildableInMarketplace();

                // Filter it down to only buildings we can afford.
                List <int> affordable = stateHelper.Player.FilterBuildingIndexesWeCanAfford(buildable);

                // Randomly pick one.
                int buildingIndex = affordable[m_random.RandomInt(0, affordable.Count - 1)];

                Logger.Log(Log.Info, $"Requesting to build {stateHelper.BuildingRules[buildingIndex].GetName()}...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateBuildBuildingAction(buildingIndex));

                if (!result.Accepted)
                {
                    await Shutdown("failed to build building.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We just bought {stateHelper.BuildingRules[buildingIndex].GetName()}!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.TvStationPayout))
            {
                // Our Tv Station activated! Let's take 5 coins from a player at random.
                GamePlayer randomPlayer = GetRandomPlayer(stateHelper);

                Logger.Log(Log.Info, $"Our Tv Station was activated, let's take coins from player {randomPlayer.Name}!");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateTvStationPayoutAction(randomPlayer.PlayerIndex));

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to respond to tv station payout.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We taken coins from player {randomPlayer.Name} for our tv station!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.BusinessCenterSwap))
            {
                // Our Business Center activated! Let's randomly pick a player and building to swap.
                GamePlayer   randomPlayer  = GetRandomPlayer(stateHelper);
                BuildingBase ourBuilding   = GetRandomOwnedNonMajorBuidling(stateHelper, null);
                BuildingBase theirBuilding = GetRandomOwnedNonMajorBuidling(stateHelper, randomPlayer.PlayerIndex);

                GameActionResponse result;
                if (randomPlayer == null || ourBuilding == null || theirBuilding == null)
                {
                    // If there aren't any building we can use, skip the action.
                    Logger.Log(Log.Info, $"Our Business Center was activated, but there weren't the correct building to swap. So we will skip!");
                    result = await m_bot.SendAction(GameAction <object> .CreateBusinessCenterSwapAction(0, 0, 0, true));
                }
                else
                {
                    Logger.Log(Log.Info, $"Our Business Center was activated, swap our {ourBuilding.GetName()} for {randomPlayer.Name}'s {theirBuilding.GetName()}!");
                    result = await m_bot.SendAction(GameAction <object> .CreateBusinessCenterSwapAction(randomPlayer.PlayerIndex, ourBuilding.GetBuildingIndex(), theirBuilding.GetBuildingIndex()));
                }

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to respond to business center swap.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"Business center swap done!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.EndTurn))
            {
                // If we can't roll the dice or build a building, we must not have enough funds.
                // Just end the turn.

                Logger.Log(Log.Info, "There's nothing to do, requesting turn end...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateEndTurnAction());

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to end our turn.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We have {stateHelper.Player.GetPlayer().Coins} coins and can't buy anything, so we ended the turn.");
                }
                return;
            }

            Logger.Log(Log.Error, $"Hmm, we were asked for an action but didn't know what to do with...");
            foreach (GameActionType type in actionRequest.PossibleActions)
            {
                Logger.Log(Log.Error, $"  ... {type.ToString()}");
                await Shutdown("received an unknown action.", null);
            }
        }
示例#20
0
        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
        }