public void SelectOrdered_RandomlyGeneratedCases() { Random rand = new Random(Seed: 101); const int generatedTestCaseCount = 1000; for (int _ = 0; _ < generatedTestCaseCount; _++) { TestUserManager.ResetTestUsers(); // Test should work with any values (undefined behavior for negatives) int numUsers = rand.Next(3, 50); int numInputsWanted = (numUsers * rand.Next(0, 5)) + rand.Next(1, 50); Dictionary <Guid, List <UserCreatedObject> > userIdToObjectList = new Dictionary <Guid, List <UserCreatedObject> >(); for (int userId = 0; userId < numUsers; userId++) { // Based on implementation of SelectOrdered, 0 members is equivalent to numUsers--. int numMembersForUser = rand.Next(1, 8); userIdToObjectList[TestUserManager.GetTestUser(userId).Id] = new List <UserCreatedObject>(); for (int objIter = 0; objIter < numMembersForUser; objIter++) { userIdToObjectList[TestUserManager.GetTestUser(userId).Id].Add( new UserCreatedObject() { Owner = TestUserManager.GetTestUser(userId), Id = Guid.NewGuid() }); } } List <UserCreatedObject> inputObjects = userIdToObjectList.Values.SelectMany(val => val).ToList(); List <UserCreatedObject> returnedObjects = MemberHelpers <UserCreatedObject> .Select_Ordered( inputObjects, numInputsWanted).ToList(); if (inputObjects.Count <= numInputsWanted) { Assert.AreEqual(inputObjects.Count, returnedObjects.Count); Assert.IsTrue(returnedObjects.HasSameElements(inputObjects)); continue; } Assert.AreEqual(numInputsWanted, returnedObjects.Count); Dictionary <Guid, List <UserCreatedObject> > groupedReturnedObjects = userIdToObjectList.Keys.Select( (userId) => (userId, returnedObjects.Where((member) => member.Source == userId).ToList())) .ToDictionary((val) => val.Item1, (val) => val.Item2); int largestGroup = groupedReturnedObjects.Values.Max((val) => val.Count); Assert.IsTrue(groupedReturnedObjects.All((val) => (val.Value.Count >= largestGroup - 1) || (userIdToObjectList[val.Key].Count == val.Value.Count))); Assert.IsTrue(groupedReturnedObjects.All((val) => (val.Value.Zip(userIdToObjectList[val.Key].Take(val.Value.Count)).All((pair) => pair.First?.Id == pair.Second?.Id)))); } }
public void SelectOrdered(int[] inputIds, int numInputsWanted, int[] expectedIds) { TestUserManager.ResetTestUsers(); List <UserCreatedObject> inputObjects = inputIds.Select(id => new UserCreatedObject() { Owner = TestUserManager.GetTestUser(id), Id = TestUserManager.GetTestUser(id).Id }).ToList(); List <UserCreatedObject> expectedObjects = expectedIds.Select(id => new UserCreatedObject() { Owner = TestUserManager.GetTestUser(id), Id = TestUserManager.GetTestUser(id).Id }).ToList(); List <UserCreatedObject> returnedObjects = MemberHelpers <UserCreatedObject> .Select_Ordered(inputObjects, numInputsWanted).ToList(); Assert.IsTrue(returnedObjects.HasSameElements(expectedObjects), $"Expected:{string.Join(",", expectedObjects.Select(obj => obj.Owner.DisplayName))} Actual:{string.Join(",", returnedObjects.Select(obj => obj.Owner.DisplayName))}"); }
public BattleReadyGameMode(Lobby lobby, List <ConfigureLobbyRequest.GameModeOptionRequest> gameModeOptions, StandardGameModeOptions standardOptions) { GameDuration duration = standardOptions.GameDuration; this.Lobby = lobby; int numRounds = BattleReadyConstants.NumRounds[duration]; int numPlayers = lobby.GetAllUsers().Count(); TimeSpan?setupDrawingTimer = null; TimeSpan?setupPromptTimer = null; TimeSpan?creationTimer = null; TimeSpan?votingTimer = null; int numOfEachPartInHand = (int)gameModeOptions[(int)GameModeOptionsEnum.NumEachPartInHand].ValueParsed; int numPromptsPerRound = Math.Min(numPlayers, BattleReadyConstants.MaxNumSubRounds[duration]); int minDrawingsRequired = numOfEachPartInHand * 3; // the amount to make one playerHand to give everyone int expectedPromptsPerUser = (int)Math.Ceiling(1.0 * numPromptsPerRound * numRounds / lobby.GetAllUsers().Count); int expectedDrawingsPerUser = Math.Max((minDrawingsRequired / numPlayers + 1) * 2, BattleReadyConstants.NumDrawingsPerPlayer[duration]); if (standardOptions.TimerEnabled) { setupDrawingTimer = BattleReadyConstants.SetupPerDrawingTimer[duration]; setupPromptTimer = BattleReadyConstants.SetupPerPromptTimer[duration]; creationTimer = BattleReadyConstants.PerCreationTimer[duration]; votingTimer = BattleReadyConstants.VotingTimer[duration]; } SetupDrawings_GS setupDrawing = new SetupDrawings_GS( lobby: lobby, drawings: this.Drawings, numExpectedPerUser: expectedDrawingsPerUser, setupDurration: setupDrawingTimer * expectedDrawingsPerUser); SetupPrompts_GS setupPrompt = new SetupPrompts_GS( lobby: lobby, prompts: Prompts, numExpectedPerUser: expectedPromptsPerUser, setupDuration: setupPromptTimer); List <Prompt> battlePrompts = new List <Prompt>(); IReadOnlyList <PeopleUserDrawing> headDrawings = new List <PeopleUserDrawing>(); IReadOnlyList <PeopleUserDrawing> bodyDrawings = new List <PeopleUserDrawing>(); IReadOnlyList <PeopleUserDrawing> legsDrawings = new List <PeopleUserDrawing>(); setupDrawing.AddExitListener(() => { // Trim extra prompts/drawings. headDrawings = Drawings.ToList().FindAll((drawing) => drawing.Type == BodyPartType.Head); bodyDrawings = Drawings.ToList().FindAll((drawing) => drawing.Type == BodyPartType.Body); legsDrawings = Drawings.ToList().FindAll((drawing) => drawing.Type == BodyPartType.Legs); }); int numPromptsPerUserPerRound = 0; // Set during below exit listener. setupPrompt.AddExitListener(() => { battlePrompts = MemberHelpers <Prompt> .Select_Ordered(Prompts.OrderBy(prompt => prompt.CreationTime).ToList(), numPromptsPerRound * numRounds); numRounds = (battlePrompts.Count - 1) / numPromptsPerRound + 1; numPromptsPerRound = (int)Math.Ceiling(1.0 * battlePrompts.Count / numRounds); numPromptsPerUserPerRound = Math.Max(1, numPromptsPerRound / 2); int maxNumUsersPerPrompt = Math.Min(12, (int)Math.Ceiling(1.0 * numPlayers * numPromptsPerUserPerRound / numPromptsPerRound)); foreach (Prompt prompt in battlePrompts) { prompt.MaxMemberCount = maxNumUsersPerPrompt; } }); List <GameState> creationGameStates = new List <GameState>(); List <GameState> votingGameStates = new List <GameState>(); List <GameState> voteRevealedGameStates = new List <GameState>(); List <GameState> scoreboardGameStates = new List <GameState>(); int countRounds = 0; #region GameState Generators GameState CreateContestantCreationGamestate() { RoundTracker.ResetRoundVariables(); List <Prompt> prompts = battlePrompts.Take(numPromptsPerRound).ToList(); battlePrompts.RemoveRange(0, prompts.Count); List <IGroup <User> > assignments = MemberHelpers <User> .Assign( prompts.Cast <IConstraints <User> >().ToList(), lobby.GetAllUsers().ToList(), duplicateMembers : (int)Math.Ceiling((1.0 * prompts.Count / numPromptsPerRound) * numPromptsPerUserPerRound)); var pairings = prompts.Zip(assignments); foreach ((Prompt prompt, IGroup <User> users) in pairings) { foreach (User user in users.Members) { prompt.UsersToUserHands.TryAdd(user, new Prompt.UserHand { // Users have even probabilities regardless of how many drawings they submitted. HeadChoices = MemberHelpers <PeopleUserDrawing> .Select_DynamicWeightedRandom(headDrawings, numOfEachPartInHand), BodyChoices = MemberHelpers <PeopleUserDrawing> .Select_DynamicWeightedRandom(bodyDrawings, numOfEachPartInHand), LegChoices = MemberHelpers <PeopleUserDrawing> .Select_DynamicWeightedRandom(legsDrawings, numOfEachPartInHand), Owner = user }); if (!RoundTracker.UsersToAssignedPrompts.ContainsKey(user)) { RoundTracker.UsersToAssignedPrompts.Add(user, new List <Prompt>()); } RoundTracker.UsersToAssignedPrompts[user].Add(prompt); } } GameState toReturn = new ContestantCreation_GS( lobby: lobby, roundTracker: RoundTracker, creationDuration: creationTimer); toReturn.Transition(CreateVotingGameStates(prompts)); return(toReturn); } Func <StateChain> CreateVotingGameStates(List <Prompt> roundPrompts) { return(() => { StateChain voting = new StateChain( stateGenerator: (int counter) => { if (counter < roundPrompts.Count) { Prompt roundPrompt = roundPrompts[counter]; return GetVotingAndRevealState(roundPrompt, votingTimer); } else { // Stops the chain. return null; } }); voting.Transition(CreateScoreGameState(roundPrompts)); return voting; }); } Func <GameState> CreateScoreGameState(List <Prompt> roundPrompts) { return(() => { List <Person> winnersPeople = roundPrompts.Select((prompt) => (Person)prompt.UsersToUserHands[prompt.Winner]).ToList(); countRounds++; GameState displayPeople = new DisplayPeople_GS( lobby: lobby, title: "Here are your winners", peopleList: winnersPeople, imageTitle: (person) => roundPrompts[winnersPeople.IndexOf(person)].Text, imageHeader: (person) => person.Name ); if (battlePrompts.Count <= 0) { GameState finalScoreBoard = new ScoreBoardGameState( lobby: lobby, title: "Final Scores"); displayPeople.Transition(finalScoreBoard); finalScoreBoard.Transition(this.Exit); } else { GameState scoreBoard = new ScoreBoardGameState( lobby: lobby); displayPeople.Transition(scoreBoard); scoreBoard.Transition(CreateContestantCreationGamestate); } return displayPeople; }); } #endregion this.Entrance.Transition(setupDrawing); setupDrawing.Transition(setupPrompt); setupPrompt.Transition(CreateContestantCreationGamestate); }