Rewrite round generation and add unit test

This commit is contained in:
Flamefire committed 2014-12-16 23:36:49 +01:00
1 parent 84e9163b96
commit 6d494b64b3
11 files changed
+240 -386

No files matched your search

+68 -176
View File
@@ -17,218 +17,110 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using VocaluxeLib.Utils.Combinatorics;
namespace VocaluxeLib.PartyModes.Challenge
{
public class CChallengeRounds
{
private readonly Random _Rand;
private readonly int _NumPlayer;
public readonly List<CCombination> Rounds;
private readonly List<CRound> _Rounds = new List<CRound>();
public int Count
{
get { return Rounds.Count; }
get { return _Rounds.Count; }
}
public CCombination this[int index]
public CRound this[int index]
{
get { return Rounds[index]; }
get { return _Rounds[index]; }
}
public CChallengeRounds(int numRounds, int numPlayer, int numPlayerAtOnce)
public CChallengeRounds(int numRounds, int numPlayer, int playersPerRound)
{
Rounds = new List<CCombination>();
_Rand = new Random(DateTime.Now.Millisecond);
if (numRounds < 1 || numPlayer < 1 || playersPerRound < 1)
throw new ArgumentException("Invalid paramters for the rounds");
if (numPlayerAtOnce < 1 || numRounds < 1 || numPlayer == 0)
_NumPlayer = 0;
else
{
_NumPlayer = numPlayer;
_BuildRounds(numRounds, numPlayerAtOnce, _Rand);
}
if (playersPerRound > numPlayer)
playersPerRound = numPlayer;
_BuildRounds(numRounds, numPlayer, playersPerRound);
}
public CCombination GetRound(int roundNr)
/// <summary>
/// Divides players in 2 categories: Those how sung the most and the others
/// </summary>
/// <param name="numSung">List matching the playerIndex to the number of songs sung</param>
private static List<int> _GetPlayersForRound(IList<int> numSung)
{
if (roundNr >= Rounds.Count || _NumPlayer == 0 || Rounds.Count == 0)
return null;
return Rounds[roundNr];
List<int> mustSing = new List<int>();
int max = numSung.Max();
for (int i = 0; i < numSung.Count; i++)
{
if (numSung[i] < max)
mustSing.Add(i);
}
return mustSing;
}
private void _BuildRounds(int numRounds, int numPlayerAtOnce, Random rand)
private static void _AddCombinations(int numPlayer, int playersPerRound, List<CRound> combinations)
{
CCombinations combinations = new CCombinations(_NumPlayer, numPlayerAtOnce, rand);
Rounds.Add(combinations.GetNextCombination(null));
for (int i = 1; i < numRounds; i++)
Rounds.Add(combinations.GetNextCombination(_GetPlayerDemand(i)));
List<int> input = new List<int>(numPlayer);
for (int i = 0; i < numPlayer; i++)
input.Add(i);
CCombinations<int> combs = new CCombinations<int>(input, playersPerRound);
combinations.AddRange(combs.Select(combination => new CRound(combination)));
combinations.Shuffle();
}
private IEnumerable<int> _GetPlayerDemand(int roundIndex)
private static CRound _GetMatchingCombination(List<int> playersInRound, List<CRound> combinations)
{
List<int> numPlayed = new List<int>(_NumPlayer);
for (int i = 0; i < _NumPlayer; i++)
numPlayed.Add(0);
for (int i = 0; i < roundIndex; i++)
foreach (CRound round in combinations)
{
foreach (int playerIndex in Rounds[i].Player)
numPlayed[playerIndex]++;
int matching = round.Players.Count(playersInRound.Contains);
// A valid round contains only players from playersInRound or all players from playersInRound (and some others)
if (matching == round.Players.Count || matching == playersInRound.Count)
return round;
}
Debug.Assert(false, "This should not happen!");
return combinations[0];
}
int max = numPlayed.Max();
int playersPerRound = Rounds[0].Player.Count;
List<int> result = new List<int>();
List<int> other = new List<int>();
List<int> last = new List<int>();
for (int i = 0; i < _NumPlayer; i++)
private void _BuildRounds(int numRounds, int numPlayer, int playersPerRound)
{
// What we want is that every player sung the same amount of songs
// So we keep track how many songs each palyer sung
List<int> numSung = new List<int>(numPlayer);
for (int i = 0; i < numPlayer; i++)
numSung.Add(0);
List<CRound> combinations = new List<CRound>();
// Posibly add more rounds than requested if the song count per player is unequal
for (int i = 0; i < numRounds * 10; i++)
{
if (roundIndex == 0 || numPlayed[i] < max)
{
if (roundIndex == 0 || roundIndex > 0 && numPlayed[i] < max && !Rounds[roundIndex - 1].Contains(i))
result.Add(i);
else if (numPlayed[i] < max)
other.Add(i);
}
else
{
if (roundIndex > 0)
{
if (!Rounds[roundIndex - 1].Contains(i))
other.Add(i);
else
last.Add(i);
}
else
last.Add(i);
}
if (combinations.Count == 0)
_AddCombinations(numPlayer, playersPerRound, combinations);
List<int> playersInRound = _GetPlayersForRound(numSung);
CRound curRound = _GetMatchingCombination(playersInRound, combinations);
foreach (int player in curRound.Players)
numSung[player]++;
_Rounds.Add(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;
}
while (result.Count < playersPerRound && other.Count > 0)
{
int n = other.Count;
int r = _Rand.Next(n);
result.Add(other[r]);
other.RemoveAt(r);
}
while (result.Count < playersPerRound)
{
int n = last.Count;
int r = _Rand.Next(n);
result.Add(last[r]);
last.RemoveAt(r);
}
while (result.Count > playersPerRound)
{
int n = result.Count;
int r = _Rand.Next(n);
result.RemoveAt(r);
}
result.Sort();
return result;
if (_Rounds.Count != numRounds)
CBase.Log.LogDebug("Number of rounds does not match. Expected: " + numRounds + ", Is: " + _Rounds.Count + " for " + numPlayer + "/" + playersPerRound);
}
}
class CCombinations
public class CRound
{
private readonly List<CCombination> _Combs;
private readonly Random _Rand;
private readonly int _NumPlayer;
private readonly int _NumMics;
public readonly List<int> Players;
public CCombinations(int numPlayer, int numMics, Random rand)
public CRound(List<int> players)
{
_Combs = new List<CCombination>();
_NumMics = numMics;
_NumPlayer = numPlayer;
_Rand = rand;
}
public CCombination GetNextCombination(IEnumerable<int> playerNrDemand)
{
if (_Combs.Count == 0)
_Create();
if (_NumPlayer == _NumMics)
return _Combs[0];
//filter against PlayerNrDemand
List<CCombination> combsFiltered = new List<CCombination>();
if (playerNrDemand != null)
combsFiltered.AddRange(_Combs.Where(t => t.ContainsAll(playerNrDemand)));
//1st fallback
if (playerNrDemand != null && combsFiltered.Count == 0)
combsFiltered.AddRange(_Combs.Where(t => t.ContainsAny(playerNrDemand)));
//2nd fallback
if (combsFiltered.Count == 0)
combsFiltered.AddRange(_Combs);
int num = combsFiltered.Count;
int rand = _Rand.Next(num);
CCombination c = new CCombination();
for (int i = 0; i < combsFiltered[rand].Player.Count; i++)
c.Player.Add(combsFiltered[rand].Player[i]);
_Combs.Remove(combsFiltered[rand]);
return combsFiltered[rand];
}
private void _Create()
{
_Combs.Clear();
int num = (int)Math.Pow(2, _NumPlayer);
for (int i = 1; i < num; i++)
{
CCombination c = new CCombination();
for (int j = 0; j < _NumPlayer; j++)
{
if ((i & (1 << j)) > 0)
c.Player.Add(j);
}
if (c.Player.Count == _NumMics)
_Combs.Add(c);
}
}
}
public class CCombination
{
public readonly List<int> Player;
public CCombination()
{
Player = new List<int>();
}
public bool Contains(int playerIndex)
{
return Player.Any(p => p == playerIndex);
}
public bool ContainsAll(IEnumerable<int> playerIndices)
{
return playerIndices.All(Contains);
}
public bool ContainsAny(IEnumerable<int> playerIndices)
{
return playerIndices.Any(Contains);
Players = players.Shuffle();
}
}
}
@@ -341,13 +341,13 @@ namespace VocaluxeLib.PartyModes.Challenge
if (players.Length < GameData.NumPlayerAtOnce)
return;
CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1);
CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1];
for (int i = 0; i < GameData.NumPlayerAtOnce; i++)
{
//try to fill with the right data
if (c != null)
players[i].ProfileID = GameData.ProfileIDs[c.Player[i]];
players[i].ProfileID = GameData.ProfileIDs[c.Players[i]];
else
players[i].ProfileID = -1;
}
@@ -413,15 +413,10 @@ namespace VocaluxeLib.PartyModes.Challenge
}
_ScreenSongOptions.Selection.TeamNames = new string[GameData.NumPlayerAtOnce];
CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1);
CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1];
for (int i = 0; i < GameData.NumPlayerAtOnce; i++)
{
if (c != null)
_ScreenSongOptions.Selection.TeamNames[i] = CBase.Profiles.GetPlayerName(GameData.ProfileIDs[c.Player[i]]);
else
_ScreenSongOptions.Selection.TeamNames[i] = "foobar";
}
_ScreenSongOptions.Selection.TeamNames[i] = CBase.Profiles.GetPlayerName(GameData.ProfileIDs[c.Players[i]]);
}
private void _UpdateScores()
@@ -340,7 +340,7 @@ namespace VocaluxeLib.PartyModes.Challenge
_Texts[_TextNextPlayerMessage].Visible = true;
for (int i = 0; i < _PartyMode.GameData.NumPlayerAtOnce; i++)
{
int id = _PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[_PartyMode.GameData.CurrentRoundNr - 1].Player[i]];
int id = _PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[_PartyMode.GameData.CurrentRoundNr - 1].Players[i]];
_NextPlayerStatics[i].Texture = CBase.Profiles.GetAvatar(id);
_NextPlayerTexts[i].Text = CBase.Profiles.GetPlayerName(id);
_NextPlayerTexts[i].Color = CBase.Themes.GetPlayerColor(i + 1);
@@ -452,14 +452,14 @@ namespace VocaluxeLib.PartyModes.Challenge
{
for (int p = 0; p < _RoundsTable[i].TextPlayer.Count; p++)
{
if (_PartyMode.GameData.Rounds.Count > i + _RoundsTableOffset && _PartyMode.GameData.Rounds[i + _RoundsTableOffset].Player.Count > p)
if (_PartyMode.GameData.Rounds.Count > i + _RoundsTableOffset && _PartyMode.GameData.Rounds[i + _RoundsTableOffset].Players.Count > p)
{
_RoundsTable[i].Number.Visible = true;
_RoundsTable[i].TextPlayer[p].Visible = true;
_RoundsTable[i].TextScores[p].Visible = true;
_RoundsTable[i].Number.Text = (i + 1 + _RoundsTableOffset) + ")";
_RoundsTable[i].TextPlayer[p].Text =
CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[i + _RoundsTableOffset].Player[p]]);
CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[i + _RoundsTableOffset].Players[p]]);
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
if ((_PartyMode.GameData.CurrentRoundNr - 1) > i + _RoundsTableOffset)
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression
@@ -17,218 +17,110 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using VocaluxeLib.Utils.Combinatorics;
namespace VocaluxeLib.PartyModes.ChallengeMedley
{
public class CChallengeRounds
{
private readonly Random _Rand;
private readonly int _NumPlayer;
public readonly List<CCombination> Rounds;
private readonly List<CRound> _Rounds = new List<CRound>();
public int Count
{
get { return Rounds.Count; }
get { return _Rounds.Count; }
}
public CCombination this[int index]
public CRound this[int index]
{
get { return Rounds[index]; }
get { return _Rounds[index]; }
}
public CChallengeRounds(int numRounds, int numPlayer, int numPlayerAtOnce)
public CChallengeRounds(int numRounds, int numPlayer, int playersPerRound)
{
Rounds = new List<CCombination>();
_Rand = new Random(DateTime.Now.Millisecond);
if (numRounds < 1 || numPlayer < 1 || playersPerRound < 1)
throw new ArgumentException("Invalid paramters for the rounds");
if (numPlayerAtOnce < 1 || numRounds < 1 || numPlayer == 0)
_NumPlayer = 0;
else
{
_NumPlayer = numPlayer;
_BuildRounds(numRounds, numPlayerAtOnce, _Rand);
}
if (playersPerRound > numPlayer)
playersPerRound = numPlayer;
_BuildRounds(numRounds, numPlayer, playersPerRound);
}
public CCombination GetRound(int roundNr)
/// <summary>
/// Divides players in 2 categories: Those how sung the most and the others
/// </summary>
/// <param name="numSung">List matching the playerIndex to the number of songs sung</param>
private static List<int> _GetPlayersForRound(IList<int> numSung)
{
if (roundNr >= Rounds.Count || _NumPlayer == 0 || Rounds.Count == 0)
return null;
return Rounds[roundNr];
List<int> mustSing = new List<int>();
int max = numSung.Max();
for (int i = 0; i < numSung.Count; i++)
{
if (numSung[i] < max)
mustSing.Add(i);
}
return mustSing;
}
private void _BuildRounds(int numRounds, int numPlayerAtOnce, Random rand)
private static void _AddCombinations(int numPlayer, int playersPerRound, List<CRound> combinations)
{
CCombinations combinations = new CCombinations(_NumPlayer, numPlayerAtOnce, rand);
Rounds.Add(combinations.GetNextCombination(null));
for (int i = 1; i < numRounds; i++)
Rounds.Add(combinations.GetNextCombination(_GetPlayerDemand(i)));
List<int> input = new List<int>(numPlayer);
for (int i = 0; i < numPlayer; i++)
input.Add(i);
CCombinations<int> combs = new CCombinations<int>(input, playersPerRound);
combinations.AddRange(combs.Select(combination => new CRound(combination)));
combinations.Shuffle();
}
private IEnumerable<int> _GetPlayerDemand(int roundIndex)
private static CRound _GetMatchingCombination(List<int> playersInRound, List<CRound> combinations)
{
List<int> numPlayed = new List<int>(_NumPlayer);
for (int i = 0; i < _NumPlayer; i++)
numPlayed.Add(0);
for (int i = 0; i < roundIndex; i++)
foreach (CRound round in combinations)
{
foreach (int playerIndex in Rounds[i].Player)
numPlayed[playerIndex]++;
int matching = round.Players.Count(playersInRound.Contains);
// A valid round contains only players from playersInRound or all players from playersInRound (and some others)
if (matching == round.Players.Count || matching == playersInRound.Count)
return round;
}
Debug.Assert(false, "This should not happen!");
return combinations[0];
}
int max = numPlayed.Max();
int num = Rounds[0].Player.Count;
List<int> result = new List<int>();
List<int> other = new List<int>();
List<int> last = new List<int>();
for (int i = 0; i < numPlayed.Count; i++)
private void _BuildRounds(int numRounds, int numPlayer, int playersPerRound)
{
// What we want is that every player sung the same amount of songs
// So we keep track how many songs each palyer sung
List<int> numSung = new List<int>(numPlayer);
for (int i = 0; i < numPlayer; i++)
numSung.Add(0);
List<CRound> combinations = new List<CRound>();
// Posibly add more rounds than requested if the song count per player is unequal
for (int i = 0; i < numRounds * 10; i++)
{
if (roundIndex == 0 || numPlayed[i] < max)
{
if (roundIndex == 0 || roundIndex > 0 && numPlayed[i] < max && !Rounds[roundIndex - 1].IsAvailable(i))
result.Add(i);
else if (numPlayed[i] < max)
other.Add(i);
}
else
{
if (roundIndex > 0)
{
if (!Rounds[roundIndex - 1].IsAvailable(i))
other.Add(i);
else
last.Add(i);
}
else
last.Add(i);
}
if (combinations.Count == 0)
_AddCombinations(numPlayer, playersPerRound, combinations);
List<int> playersInRound = _GetPlayersForRound(numSung);
CRound curRound = _GetMatchingCombination(playersInRound, combinations);
foreach (int player in curRound.Players)
numSung[player]++;
_Rounds.Add(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;
}
while (result.Count < num && other.Count > 0)
{
int n = other.Count;
int r = _Rand.Next(n);
result.Add(other[r]);
other.RemoveAt(r);
}
while (result.Count < num)
{
int n = last.Count;
int r = _Rand.Next(n);
result.Add(last[r]);
last.RemoveAt(r);
}
while (result.Count > num)
{
int n = result.Count;
int r = _Rand.Next(n);
result.RemoveAt(r);
}
result.Sort();
return result;
if (_Rounds.Count != numRounds)
CBase.Log.LogDebug("Number of rounds does not match. Expected: " + numRounds + ", Is: " + _Rounds.Count + " for " + numPlayer + "/" + playersPerRound);
}
}
class CCombinations
public class CRound
{
private readonly List<CCombination> _Combs;
private readonly Random _Rand;
private readonly int _NumPlayer;
private readonly int _NumMics;
public readonly List<int> Players;
public CCombinations(int numPlayer, int numMics, Random rand)
public CRound(List<int> players)
{
_Combs = new List<CCombination>();
_NumMics = numMics;
_NumPlayer = numPlayer;
_Rand = rand;
}
public CCombination GetNextCombination(IEnumerable<int> playerNrDemand)
{
if (_Combs.Count == 0)
_Create();
if (_NumPlayer == _NumMics)
return _Combs[0];
//filter against PlayerNrDemand
List<CCombination> combsFiltered = new List<CCombination>();
if (playerNrDemand != null)
combsFiltered.AddRange(_Combs.Where(t => t.IsAvailableAll(playerNrDemand)));
//1st fallback
if (playerNrDemand != null && combsFiltered.Count == 0)
combsFiltered.AddRange(_Combs.Where(t => t.IsAvailableSomeone(playerNrDemand)));
//2nd fallback
if (combsFiltered.Count == 0)
combsFiltered.AddRange(_Combs);
int num = combsFiltered.Count;
int rand = _Rand.Next(num);
CCombination c = new CCombination();
for (int i = 0; i < combsFiltered[rand].Player.Count; i++)
c.Player.Add(combsFiltered[rand].Player[i]);
_Combs.Remove(combsFiltered[rand]);
return combsFiltered[rand];
}
private void _Create()
{
_Combs.Clear();
int num = (int)Math.Pow(2, _NumPlayer);
for (int i = 1; i <= num; i++)
{
CCombination c = new CCombination();
for (int j = 0; j < _NumPlayer; j++)
{
if ((i & (1 << j)) > 0)
c.Player.Add(j);
}
if (c.Player.Count == _NumMics)
_Combs.Add(c);
}
}
}
public class CCombination
{
public readonly List<int> Player;
public CCombination()
{
Player = new List<int>();
}
public bool IsAvailable(int playerIndex)
{
return Player.Any(p => p == playerIndex);
}
public bool IsAvailableAll(IEnumerable<int> playerIndices)
{
return playerIndices.All(IsAvailable);
}
public bool IsAvailableSomeone(IEnumerable<int> playerIndices)
{
return playerIndices.Any(IsAvailable);
Players = players.Shuffle();
}
}
}
@@ -366,13 +366,13 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
if (players.Length < GameData.NumPlayerAtOnce)
return false;
CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1);
CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1];
for (int i = 0; i < GameData.NumPlayerAtOnce; i++)
{
//try to fill with the right data
if (c != null)
players[i].ProfileID = GameData.ProfileIDs[c.Player[i]];
players[i].ProfileID = GameData.ProfileIDs[c.Players[i]];
else
players[i].ProfileID = -1;
}
@@ -475,14 +475,14 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
}
_ScreenSongOptions.Selection.TeamNames = new string[GameData.NumPlayerAtOnce];
CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1);
CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1];
for (int i = 0; i < GameData.NumPlayerAtOnce; i++)
{
if (c != null)
{
if (GameData.ProfileIDs[c.Player[i]] < profiles.Length)
_ScreenSongOptions.Selection.TeamNames[i] = profiles[GameData.ProfileIDs[c.Player[i]]].PlayerName;
if (GameData.ProfileIDs[c.Players[i]] < profiles.Length)
_ScreenSongOptions.Selection.TeamNames[i] = profiles[GameData.ProfileIDs[c.Players[i]]].PlayerName;
else
_ScreenSongOptions.Selection.TeamNames[i] = "foobar";
}
@@ -340,7 +340,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
_Texts[_TextNextPlayerMessage].Visible = true;
for (int i = 0; i < _PartyMode.GameData.NumPlayerAtOnce; i++)
{
int id = _PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[_PartyMode.GameData.CurrentRoundNr - 1].Player[i]];
int id = _PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[_PartyMode.GameData.CurrentRoundNr - 1].Players[i]];
_NextPlayerStatics[i].Texture = CBase.Profiles.GetAvatar(id);
_NextPlayerTexts[i].Text = CBase.Profiles.GetPlayerName(id);
_NextPlayerTexts[i].Color = CBase.Themes.GetPlayerColor(i + 1);
@@ -452,14 +452,14 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
{
for (int p = 0; p < _RoundsTable[i].TextPlayer.Count; p++)
{
if (_PartyMode.GameData.Rounds.Count > i + _RoundsTableOffset && _PartyMode.GameData.Rounds[i + _RoundsTableOffset].Player.Count > p)
if (_PartyMode.GameData.Rounds.Count > i + _RoundsTableOffset && _PartyMode.GameData.Rounds[i + _RoundsTableOffset].Players.Count > p)
{
_RoundsTable[i].Number.Visible = true;
_RoundsTable[i].TextPlayer[p].Visible = true;
_RoundsTable[i].TextScores[p].Visible = true;
_RoundsTable[i].Number.Text = (i + 1 + _RoundsTableOffset) + ")";
_RoundsTable[i].TextPlayer[p].Text =
CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[i + _RoundsTableOffset].Player[p]]);
CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[i + _RoundsTableOffset].Players[p]]);
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
if ((_PartyMode.GameData.CurrentRoundNr - 1) > i + _RoundsTableOffset)
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression
@@ -415,17 +415,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe
}
}
private static void _Shuffle<T>(IList<T> list)
{
for (int n = list.Count - 1; n >= 1; n--)
{
int k = CBase.Game.GetRandom(n);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
public void UpdateSongList()
{
if (GameData.Songs.Count > 0)
@@ -455,7 +444,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
CBase.Songs.SetCategory(-1);
break;
}
_Shuffle(GameData.Songs);
GameData.Songs.Shuffle();
}
private void _UpdatePlayerList()
+12
View File
@@ -178,6 +178,18 @@ namespace VocaluxeLib
rect.Z);
}
public static List<T> Shuffle<T>(this List<T> list)
{
for (int n = list.Count - 1; n >= 1; n--)
{
int k = CBase.Game.GetRandom(n);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
return list;
}
public static Size GetSize(this Bitmap bmp)
{
return new Size(bmp.Width, bmp.Height);
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace VocaluxeLib.Utils.Combinatorics
{
@@ -143,8 +144,7 @@ namespace VocaluxeLib.Utils.Combinatorics
get
{
List<T> result = new List<T>(_K);
for (int i = 0; i < _K; i++)
result.Add(_Parent._Values[_CurSet[i]]);
result.AddRange(_CurSet.Select(i => _Parent._Values[i]));
return result;
}
}
+69
View File
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Vocaluxe.Base;
using VocaluxeLib;
using VocaluxeLib.PartyModes.Challenge;
namespace VocaluxeTests
{
[TestClass]
public class CPartyModeTests
{
[TestMethod]
public void TestRoundBoundaries()
{
// ReSharper disable ObjectCreationAsStatement
new CChallengeRounds(1, 1, 1); // Should succeed
// ReSharper restore ObjectCreationAsStatement
for (int inv = -1; inv <= 0; inv++)
{
int invL = inv;
CTestHelpers.AssertFail<ArgumentException>(() => new CChallengeRounds(invL, 1, 1));
CTestHelpers.AssertFail<ArgumentException>(() => new CChallengeRounds(1, invL, 1));
CTestHelpers.AssertFail<ArgumentException>(() => new CChallengeRounds(1, 1, invL));
}
}
private static void _CheckRounds(CChallengeRounds rounds, int numPlayer)
{
List<int> numSongs = new List<int>(numPlayer);
for (int i = 0; i < numPlayer; i++)
numSongs.Add(0);
for (int i = 0; i < rounds.Count; i++)
{
foreach (int player in rounds[i].Players)
{
Assert.IsTrue(player >= 0 && player < numPlayer);
numSongs[player]++;
}
}
Assert.IsTrue(numSongs.Min() == numSongs.Max(), "Some players have more songs than others");
}
[TestMethod]
public void TestRoundGeneration()
{
CBase.Game = new CBGame();
CLog.Init();
CBase.Log = new CBlog();
for (int i = 0; i < 10; i++)
{
for (int numPlayer = 1; numPlayer <= 20; numPlayer++)
{
for (int numMic = 1; numMic <= 6; numMic++)
{
int roundFactor = (numPlayer % numMic == 0) ? numPlayer / numMic : numPlayer;
for (int numRounds = roundFactor; numRounds <= 100 && numRounds <= roundFactor * 5; numRounds += roundFactor)
{
CChallengeRounds rounds = new CChallengeRounds(numRounds, numPlayer, numMic);
Assert.IsTrue(rounds.Count >= numRounds);
_CheckRounds(rounds, numPlayer);
}
}
}
}
}
}
}
+5
View File
@@ -73,9 +73,14 @@
<Compile Include="CTestHelpers.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="CombinatoricsTest.cs" />
<Compile Include="PartyModeTests.cs" />
<Compile Include="XmlSerializerTest.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PartyModes\PartyModeChallenge\PartyModeChallenge.csproj">
<Project>{5a4053f1-5ad5-441f-b254-d97a088127b6}</Project>
<Name>PartyModeChallenge</Name>
</ProjectReference>
<ProjectReference Include="..\VocaluxeLib\VocaluxeLib.csproj">
<Project>{d2b6ddef-e0e1-4ddf-a73a-e6acef5c95ec}</Project>
<Name>VocaluxeLib</Name>