diff --git a/PartyModes/PartyModeChallenge/CChallengeRounds.cs b/PartyModes/PartyModeChallenge/CChallengeRounds.cs index d09a3b3b..37d46362 100644 --- a/PartyModes/PartyModeChallenge/CChallengeRounds.cs +++ b/PartyModes/PartyModeChallenge/CChallengeRounds.cs @@ -46,6 +46,18 @@ namespace VocaluxeLib.PartyModes.Challenge playersPerRound = numPlayer; _BuildRounds(numRounds, numPlayer, playersPerRound); + if (Count > numRounds) + { + //Try again and take the better one + List old = new List(_Rounds); + _Rounds.Clear(); + _BuildRounds(numRounds, numPlayer, playersPerRound); + if (Count > old.Count) + { + _Rounds.Clear(); + _Rounds.AddRange(old); + } + } } /// @@ -74,7 +86,7 @@ namespace VocaluxeLib.PartyModes.Challenge combinations.Shuffle(); } - private static CRound _GetMatchingCombination(List playersInRound, List combinations) + private static CRound _GetMatchingCombination(List playersInRound, List numSung, List combinations) { foreach (CRound round in combinations) { @@ -83,8 +95,23 @@ namespace VocaluxeLib.PartyModes.Challenge if (matching == round.Players.Count || matching == playersInRound.Count) return round; } - Debug.Assert(false, "This should not happen!"); - return combinations[0]; + // It may happen, that there are only players that already sung against each other. So create a 2nd best option with the most number of players that should sing in it + int maxMatching = combinations.Max(c => c.Players.Count(playersInRound.Contains)); + List nextOptions = combinations.Where(c => c.Players.Count(playersInRound.Contains) == maxMatching).ToList(); + // And select the combination that minimizes the sum of the number of songs sung (--> favor rounds with players that sung less than others) + CRound result = null; + int minSung = int.MaxValue; + foreach (CRound round in nextOptions) + { + int curNumSung = round.Players.Sum(pl => numSung[pl]); + if (curNumSung < minSung) + { + minSung = curNumSung; + result = round; + } + } + Debug.Assert(result != null); + return result; } private void _BuildRounds(int numRounds, int numPlayer, int playersPerRound) @@ -101,16 +128,15 @@ namespace VocaluxeLib.PartyModes.Challenge if (combinations.Count == 0) _AddCombinations(numPlayer, playersPerRound, combinations); List playersInRound = _GetPlayersForRound(numSung); - CRound curRound = _GetMatchingCombination(playersInRound, combinations); + CRound curRound = _GetMatchingCombination(playersInRound, numSung, combinations); foreach (int player in curRound.Players) numSung[player]++; _Rounds.Add(curRound); + combinations.Remove(curRound); //Stop if we have enough rounds and all players sung the same amount of songs if (_Rounds.Count >= numRounds && numSung.All(ct => ct == numSung[0])) break; } - if (_Rounds.Count != numRounds) - CBase.Log.LogDebug("Number of rounds does not match. Expected: " + numRounds + ", Is: " + _Rounds.Count + " for " + numPlayer + "/" + playersPerRound); } } diff --git a/PartyModes/PartyModeChallengeMedley/CChallengeRounds.cs b/PartyModes/PartyModeChallengeMedley/CChallengeRounds.cs index caa15ccc..92e5438f 100644 --- a/PartyModes/PartyModeChallengeMedley/CChallengeRounds.cs +++ b/PartyModes/PartyModeChallengeMedley/CChallengeRounds.cs @@ -46,6 +46,18 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley playersPerRound = numPlayer; _BuildRounds(numRounds, numPlayer, playersPerRound); + if (Count > numRounds) + { + //Try again and take the better one + List old = new List(_Rounds); + _Rounds.Clear(); + _BuildRounds(numRounds, numPlayer, playersPerRound); + if (Count > old.Count) + { + _Rounds.Clear(); + _Rounds.AddRange(old); + } + } } /// @@ -74,7 +86,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley combinations.Shuffle(); } - private static CRound _GetMatchingCombination(List playersInRound, List combinations) + private static CRound _GetMatchingCombination(List playersInRound, List numSung, List combinations) { foreach (CRound round in combinations) { @@ -83,8 +95,23 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley if (matching == round.Players.Count || matching == playersInRound.Count) return round; } - Debug.Assert(false, "This should not happen!"); - return combinations[0]; + // It may happen, that there are only players that already sung against each other. So create a 2nd best option with the most number of players that should sing in it + int maxMatching = combinations.Max(c => c.Players.Count(playersInRound.Contains)); + List nextOptions = combinations.Where(c => c.Players.Count(playersInRound.Contains) == maxMatching).ToList(); + // And select the combination that minimizes the sum of the number of songs sung (--> favor rounds with players that sung less than others) + CRound result = null; + int minSung = int.MaxValue; + foreach (CRound round in nextOptions) + { + int curNumSung = round.Players.Sum(pl => numSung[pl]); + if (curNumSung < minSung) + { + minSung = curNumSung; + result = round; + } + } + Debug.Assert(result != null); + return result; } private void _BuildRounds(int numRounds, int numPlayer, int playersPerRound) @@ -101,16 +128,15 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley if (combinations.Count == 0) _AddCombinations(numPlayer, playersPerRound, combinations); List playersInRound = _GetPlayersForRound(numSung); - CRound curRound = _GetMatchingCombination(playersInRound, combinations); + CRound curRound = _GetMatchingCombination(playersInRound, numSung, combinations); foreach (int player in curRound.Players) numSung[player]++; _Rounds.Add(curRound); + combinations.Remove(curRound); //Stop if we have enough rounds and all players sung the same amount of songs if (_Rounds.Count >= numRounds && numSung.All(ct => ct == numSung[0])) break; } - if (_Rounds.Count != numRounds) - CBase.Log.LogDebug("Number of rounds does not match. Expected: " + numRounds + ", Is: " + _Rounds.Count + " for " + numPlayer + "/" + playersPerRound); } } diff --git a/VocaluxeTests/PartyModeTests.cs b/VocaluxeTests/PartyModeTests.cs index 1678b7ff..c0363123 100644 --- a/VocaluxeTests/PartyModeTests.cs +++ b/VocaluxeTests/PartyModeTests.cs @@ -60,6 +60,9 @@ namespace VocaluxeTests CChallengeRounds rounds = new CChallengeRounds(numRounds, numPlayer, numMic); Assert.IsTrue(rounds.Count >= numRounds); _CheckRounds(rounds, numPlayer); + if (rounds.Count != numRounds) + CBase.Log.LogDebug("Number of rounds does not match. Expected: " + numRounds + ", Is: " + rounds.Count + " for " + numPlayer + "/" + + ((numPlayer < numMic) ? numPlayer : numMic)); } } }