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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using VocaluxeLib.Utils.Combinatorics;
namespace VocaluxeLib.PartyModes.Challenge namespace VocaluxeLib.PartyModes.Challenge
{ {
public class CChallengeRounds public class CChallengeRounds
{ {
private readonly Random _Rand; private readonly List<CRound> _Rounds = new List<CRound>();
private readonly int _NumPlayer;
public readonly List<CCombination> Rounds;
public int Count 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>(); if (numRounds < 1 || numPlayer < 1 || playersPerRound < 1)
_Rand = new Random(DateTime.Now.Millisecond); throw new ArgumentException("Invalid paramters for the rounds");
if (numPlayerAtOnce < 1 || numRounds < 1 || numPlayer == 0) if (playersPerRound > numPlayer)
_NumPlayer = 0; playersPerRound = numPlayer;
else
{ _BuildRounds(numRounds, numPlayer, playersPerRound);
_NumPlayer = numPlayer;
_BuildRounds(numRounds, numPlayerAtOnce, _Rand);
}
} }
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) List<int> mustSing = new List<int>();
return null; int max = numSung.Max();
for (int i = 0; i < numSung.Count; i++)
return Rounds[roundNr]; {
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); List<int> input = new List<int>(numPlayer);
Rounds.Add(combinations.GetNextCombination(null)); for (int i = 0; i < numPlayer; i++)
input.Add(i);
for (int i = 1; i < numRounds; i++) CCombinations<int> combs = new CCombinations<int>(input, playersPerRound);
Rounds.Add(combinations.GetNextCombination(_GetPlayerDemand(i))); 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); foreach (CRound round in combinations)
for (int i = 0; i < _NumPlayer; i++)
numPlayed.Add(0);
for (int i = 0; i < roundIndex; i++)
{ {
foreach (int playerIndex in Rounds[i].Player) int matching = round.Players.Count(playersInRound.Contains);
numPlayed[playerIndex]++; // 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(); private void _BuildRounds(int numRounds, int numPlayer, int playersPerRound)
{
int playersPerRound = Rounds[0].Player.Count; // What we want is that every player sung the same amount of songs
List<int> result = new List<int>(); // So we keep track how many songs each palyer sung
List<int> other = new List<int>(); List<int> numSung = new List<int>(numPlayer);
List<int> last = new List<int>(); for (int i = 0; i < numPlayer; i++)
numSung.Add(0);
for (int i = 0; i < _NumPlayer; i++) 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 (combinations.Count == 0)
{ _AddCombinations(numPlayer, playersPerRound, combinations);
if (roundIndex == 0 || roundIndex > 0 && numPlayed[i] < max && !Rounds[roundIndex - 1].Contains(i)) List<int> playersInRound = _GetPlayersForRound(numSung);
result.Add(i); CRound curRound = _GetMatchingCombination(playersInRound, combinations);
else if (numPlayed[i] < max) foreach (int player in curRound.Players)
other.Add(i); numSung[player]++;
} _Rounds.Add(curRound);
else //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]))
if (roundIndex > 0) break;
{
if (!Rounds[roundIndex - 1].Contains(i))
other.Add(i);
else
last.Add(i);
}
else
last.Add(i);
}
} }
if (_Rounds.Count != numRounds)
while (result.Count < playersPerRound && other.Count > 0) CBase.Log.LogDebug("Number of rounds does not match. Expected: " + numRounds + ", Is: " + _Rounds.Count + " for " + numPlayer + "/" + playersPerRound);
{
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;
} }
} }
class CCombinations public class CRound
{ {
private readonly List<CCombination> _Combs; public readonly List<int> Players;
private readonly Random _Rand;
private readonly int _NumPlayer;
private readonly int _NumMics;
public CCombinations(int numPlayer, int numMics, Random rand) public CRound(List<int> players)
{ {
_Combs = new List<CCombination>(); Players = players.Shuffle();
_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);
} }
} }
} }
@@ -341,13 +341,13 @@ namespace VocaluxeLib.PartyModes.Challenge
if (players.Length < GameData.NumPlayerAtOnce) if (players.Length < GameData.NumPlayerAtOnce)
return; return;
CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1); CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1];
for (int i = 0; i < GameData.NumPlayerAtOnce; i++) for (int i = 0; i < GameData.NumPlayerAtOnce; i++)
{ {
//try to fill with the right data //try to fill with the right data
if (c != null) if (c != null)
players[i].ProfileID = GameData.ProfileIDs[c.Player[i]]; players[i].ProfileID = GameData.ProfileIDs[c.Players[i]];
else else
players[i].ProfileID = -1; players[i].ProfileID = -1;
} }
@@ -413,15 +413,10 @@ namespace VocaluxeLib.PartyModes.Challenge
} }
_ScreenSongOptions.Selection.TeamNames = new string[GameData.NumPlayerAtOnce]; _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++) for (int i = 0; i < GameData.NumPlayerAtOnce; i++)
{ _ScreenSongOptions.Selection.TeamNames[i] = CBase.Profiles.GetPlayerName(GameData.ProfileIDs[c.Players[i]]);
if (c != null)
_ScreenSongOptions.Selection.TeamNames[i] = CBase.Profiles.GetPlayerName(GameData.ProfileIDs[c.Player[i]]);
else
_ScreenSongOptions.Selection.TeamNames[i] = "foobar";
}
} }
private void _UpdateScores() private void _UpdateScores()
@@ -340,7 +340,7 @@ namespace VocaluxeLib.PartyModes.Challenge
_Texts[_TextNextPlayerMessage].Visible = true; _Texts[_TextNextPlayerMessage].Visible = true;
for (int i = 0; i < _PartyMode.GameData.NumPlayerAtOnce; i++) 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); _NextPlayerStatics[i].Texture = CBase.Profiles.GetAvatar(id);
_NextPlayerTexts[i].Text = CBase.Profiles.GetPlayerName(id); _NextPlayerTexts[i].Text = CBase.Profiles.GetPlayerName(id);
_NextPlayerTexts[i].Color = CBase.Themes.GetPlayerColor(i + 1); _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++) 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].Number.Visible = true;
_RoundsTable[i].TextPlayer[p].Visible = true; _RoundsTable[i].TextPlayer[p].Visible = true;
_RoundsTable[i].TextScores[p].Visible = true; _RoundsTable[i].TextScores[p].Visible = true;
_RoundsTable[i].Number.Text = (i + 1 + _RoundsTableOffset) + ")"; _RoundsTable[i].Number.Text = (i + 1 + _RoundsTableOffset) + ")";
_RoundsTable[i].TextPlayer[p].Text = _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 // ReSharper disable ConvertIfStatementToConditionalTernaryExpression
if ((_PartyMode.GameData.CurrentRoundNr - 1) > i + _RoundsTableOffset) if ((_PartyMode.GameData.CurrentRoundNr - 1) > i + _RoundsTableOffset)
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression // ReSharper restore ConvertIfStatementToConditionalTernaryExpression
@@ -17,218 +17,110 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using VocaluxeLib.Utils.Combinatorics;
namespace VocaluxeLib.PartyModes.ChallengeMedley namespace VocaluxeLib.PartyModes.ChallengeMedley
{ {
public class CChallengeRounds public class CChallengeRounds
{ {
private readonly Random _Rand; private readonly List<CRound> _Rounds = new List<CRound>();
private readonly int _NumPlayer;
public readonly List<CCombination> Rounds;
public int Count 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>(); if (numRounds < 1 || numPlayer < 1 || playersPerRound < 1)
_Rand = new Random(DateTime.Now.Millisecond); throw new ArgumentException("Invalid paramters for the rounds");
if (numPlayerAtOnce < 1 || numRounds < 1 || numPlayer == 0) if (playersPerRound > numPlayer)
_NumPlayer = 0; playersPerRound = numPlayer;
else
{ _BuildRounds(numRounds, numPlayer, playersPerRound);
_NumPlayer = numPlayer;
_BuildRounds(numRounds, numPlayerAtOnce, _Rand);
}
} }
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) List<int> mustSing = new List<int>();
return null; int max = numSung.Max();
for (int i = 0; i < numSung.Count; i++)
return Rounds[roundNr]; {
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); List<int> input = new List<int>(numPlayer);
Rounds.Add(combinations.GetNextCombination(null)); for (int i = 0; i < numPlayer; i++)
input.Add(i);
for (int i = 1; i < numRounds; i++) CCombinations<int> combs = new CCombinations<int>(input, playersPerRound);
Rounds.Add(combinations.GetNextCombination(_GetPlayerDemand(i))); 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); foreach (CRound round in combinations)
for (int i = 0; i < _NumPlayer; i++)
numPlayed.Add(0);
for (int i = 0; i < roundIndex; i++)
{ {
foreach (int playerIndex in Rounds[i].Player) int matching = round.Players.Count(playersInRound.Contains);
numPlayed[playerIndex]++; // 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(); private void _BuildRounds(int numRounds, int numPlayer, int playersPerRound)
{
int num = Rounds[0].Player.Count; // What we want is that every player sung the same amount of songs
List<int> result = new List<int>(); // So we keep track how many songs each palyer sung
List<int> other = new List<int>(); List<int> numSung = new List<int>(numPlayer);
List<int> last = new List<int>(); for (int i = 0; i < numPlayer; i++)
numSung.Add(0);
for (int i = 0; i < numPlayed.Count; i++) 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 (combinations.Count == 0)
{ _AddCombinations(numPlayer, playersPerRound, combinations);
if (roundIndex == 0 || roundIndex > 0 && numPlayed[i] < max && !Rounds[roundIndex - 1].IsAvailable(i)) List<int> playersInRound = _GetPlayersForRound(numSung);
result.Add(i); CRound curRound = _GetMatchingCombination(playersInRound, combinations);
else if (numPlayed[i] < max) foreach (int player in curRound.Players)
other.Add(i); numSung[player]++;
} _Rounds.Add(curRound);
else //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]))
if (roundIndex > 0) break;
{
if (!Rounds[roundIndex - 1].IsAvailable(i))
other.Add(i);
else
last.Add(i);
}
else
last.Add(i);
}
} }
if (_Rounds.Count != numRounds)
while (result.Count < num && other.Count > 0) CBase.Log.LogDebug("Number of rounds does not match. Expected: " + numRounds + ", Is: " + _Rounds.Count + " for " + numPlayer + "/" + playersPerRound);
{
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;
} }
} }
class CCombinations public class CRound
{ {
private readonly List<CCombination> _Combs; public readonly List<int> Players;
private readonly Random _Rand;
private readonly int _NumPlayer;
private readonly int _NumMics;
public CCombinations(int numPlayer, int numMics, Random rand) public CRound(List<int> players)
{ {
_Combs = new List<CCombination>(); Players = players.Shuffle();
_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);
} }
} }
} }
@@ -366,13 +366,13 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
if (players.Length < GameData.NumPlayerAtOnce) if (players.Length < GameData.NumPlayerAtOnce)
return false; 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++) for (int i = 0; i < GameData.NumPlayerAtOnce; i++)
{ {
//try to fill with the right data //try to fill with the right data
if (c != null) if (c != null)
players[i].ProfileID = GameData.ProfileIDs[c.Player[i]]; players[i].ProfileID = GameData.ProfileIDs[c.Players[i]];
else else
players[i].ProfileID = -1; players[i].ProfileID = -1;
} }
@@ -475,14 +475,14 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
} }
_ScreenSongOptions.Selection.TeamNames = new string[GameData.NumPlayerAtOnce]; _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++) for (int i = 0; i < GameData.NumPlayerAtOnce; i++)
{ {
if (c != null) if (c != null)
{ {
if (GameData.ProfileIDs[c.Player[i]] < profiles.Length) if (GameData.ProfileIDs[c.Players[i]] < profiles.Length)
_ScreenSongOptions.Selection.TeamNames[i] = profiles[GameData.ProfileIDs[c.Player[i]]].PlayerName; _ScreenSongOptions.Selection.TeamNames[i] = profiles[GameData.ProfileIDs[c.Players[i]]].PlayerName;
else else
_ScreenSongOptions.Selection.TeamNames[i] = "foobar"; _ScreenSongOptions.Selection.TeamNames[i] = "foobar";
} }
@@ -340,7 +340,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley
_Texts[_TextNextPlayerMessage].Visible = true; _Texts[_TextNextPlayerMessage].Visible = true;
for (int i = 0; i < _PartyMode.GameData.NumPlayerAtOnce; i++) 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); _NextPlayerStatics[i].Texture = CBase.Profiles.GetAvatar(id);
_NextPlayerTexts[i].Text = CBase.Profiles.GetPlayerName(id); _NextPlayerTexts[i].Text = CBase.Profiles.GetPlayerName(id);
_NextPlayerTexts[i].Color = CBase.Themes.GetPlayerColor(i + 1); _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++) 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].Number.Visible = true;
_RoundsTable[i].TextPlayer[p].Visible = true; _RoundsTable[i].TextPlayer[p].Visible = true;
_RoundsTable[i].TextScores[p].Visible = true; _RoundsTable[i].TextScores[p].Visible = true;
_RoundsTable[i].Number.Text = (i + 1 + _RoundsTableOffset) + ")"; _RoundsTable[i].Number.Text = (i + 1 + _RoundsTableOffset) + ")";
_RoundsTable[i].TextPlayer[p].Text = _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 // ReSharper disable ConvertIfStatementToConditionalTernaryExpression
if ((_PartyMode.GameData.CurrentRoundNr - 1) > i + _RoundsTableOffset) if ((_PartyMode.GameData.CurrentRoundNr - 1) > i + _RoundsTableOffset)
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression // 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() public void UpdateSongList()
{ {
if (GameData.Songs.Count > 0) if (GameData.Songs.Count > 0)
@@ -455,7 +444,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
CBase.Songs.SetCategory(-1); CBase.Songs.SetCategory(-1);
break; break;
} }
_Shuffle(GameData.Songs); GameData.Songs.Shuffle();
} }
private void _UpdatePlayerList() private void _UpdatePlayerList()
+12
View File
@@ -178,6 +178,18 @@ namespace VocaluxeLib
rect.Z); 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) public static Size GetSize(this Bitmap bmp)
{ {
return new Size(bmp.Width, bmp.Height); return new Size(bmp.Width, bmp.Height);
@@ -2,6 +2,7 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
namespace VocaluxeLib.Utils.Combinatorics namespace VocaluxeLib.Utils.Combinatorics
{ {
@@ -143,8 +144,7 @@ namespace VocaluxeLib.Utils.Combinatorics
get get
{ {
List<T> result = new List<T>(_K); List<T> result = new List<T>(_K);
for (int i = 0; i < _K; i++) result.AddRange(_CurSet.Select(i => _Parent._Values[i]));
result.Add(_Parent._Values[_CurSet[i]]);
return result; 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="CTestHelpers.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="CombinatoricsTest.cs" /> <Compile Include="CombinatoricsTest.cs" />
<Compile Include="PartyModeTests.cs" />
<Compile Include="XmlSerializerTest.cs" /> <Compile Include="XmlSerializerTest.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PartyModes\PartyModeChallenge\PartyModeChallenge.csproj">
<Project>{5a4053f1-5ad5-441f-b254-d97a088127b6}</Project>
<Name>PartyModeChallenge</Name>
</ProjectReference>
<ProjectReference Include="..\VocaluxeLib\VocaluxeLib.csproj"> <ProjectReference Include="..\VocaluxeLib\VocaluxeLib.csproj">
<Project>{d2b6ddef-e0e1-4ddf-a73a-e6acef5c95ec}</Project> <Project>{d2b6ddef-e0e1-4ddf-a73a-e6acef5c95ec}</Project>
<Name>VocaluxeLib</Name> <Name>VocaluxeLib</Name>