有效的方式返回组合的球员
本文关键字:组合 返回 方式 有效 | 更新日期: 2023-09-27 17:50:46
我正在编写一个多人游戏,其中每个玩家必须与他的小组中的每个玩家只玩一次。例如,如果你有3个玩家:Joe, Mary和Peter,这些将是组合:Joe &玛丽,乔&;彼得和玛丽彼得。
计算轮数的代码非常简单。因为回合数等于n!/r !* (n - r)!其中n等于参与者的数量,r等于2(因为游戏每轮有2名参与者)。
public int factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1);
}
public int calcNoOfRounds()
{
return factorial(noOfPlayers) / (factorial(2) * factorial(noOfPlayers -2));
}
然而,我坚持要产生一个有效的方法来返回实际的球员组合。我尝试了下面的代码。它的工作,但它是太手动,有我想要改进的东西。在这个代码中,我配对p1 vs p2, p2 vs p3, p3 vs p4…P (n-1) vs P (n)然后从第三个参与者开始,将这些参与者与之前的参与者进行匹配,比如p3 vs p1, p4 vs p1, p4 vs p2, p5 vs p1, p5 vs p2, p5 vs p3,等等。你认为我可以用更好的方法做这件事吗?
public void calcPlayerCombinations()
{
List<string> playerNames = new List<string>();
for (int i = 0; i < noOfPlayers; i++)
{
playerNames.Add(players[i].PlayerName);
}
for (int i = 0; i < noOfPlayers - 1; i++)
{
playerCombinations.Add(playerNames[i] + " " + playerNames[i + 1]);
}
for (int j = 3; j <= noOfPlayers; j++)
{
int counter = 1;
do
{
playerCombinations.Add(playerNames[j -1] + " " + playerNames[counter -1]);
counter++;
} while (counter != (j - 1));
}
}
我不喜欢这种方式,因为如果游戏真的在玩,你怎么希望同一个玩家连续玩6场游戏?我可以随机选择一个组合来进行一轮,但是,我仍然想知道一个更好的方法,以便将来参考。
谢谢你的帮助!
为什么你不将每个玩家(作为配对中的"第一")与比他们晚的每个玩家(作为"第二")配对呢?例如:
public static IEnumerable<string> PairPlayers(List<string> players)
{
for (int i = 0; i < players.Count - 1; i++)
{
for (int j = i + 1; j < players.Count; j++)
{
yield return players[i] + " " + players[j];
}
}
}
(显然,如果你愿意,你也可以急切地这样做。)
有可能我误解了需求。
这个例子展示了如何使用球员列表作为队列。当一名球员踢完比赛后,他们就会被放在后面,并且不太可能再次被选中。它还展示了如何做Jon Skeet所做的,但渴望(没有yield
)。
using System;
using System.Collections.Generic;
using System.Linq;
namespace SOPlayersOrder
{
class Program
{
/// <summary>
/// Represents a match up between two players.
/// It is tempting to use strings for everything, but don't do it,
/// you'll only end up having to split those strings and you will
/// not benefit from type safety.
/// </summary>
public class MatchUp
{
public string Player1 { get; set; }
public string Player2 { get; set; }
public override string ToString()
{
return string.Format("{0} vs {1}", Player1, Player2);
}
}
public static IEnumerable<MatchUp> PairPlayers(List<string> players)
{
var results = new List<MatchUp>();
for (int i = 0; i < players.Count - 1; i++)
{
for (int j = i + 1; j < players.Count; j++)
{
var matchup = new MatchUp { Player1 = players[i], Player2 = players[j] };
//yield return matchup; //this is how Jon Skeet suggested, I am showing you "eager" evaluation
results.Add(matchup);
}
}
return results;
}
public static IEnumerable<MatchUp> OrganiseGames(IEnumerable<string> players, IEnumerable<MatchUp> games)
{
var results = new List<MatchUp>();
//a list that we will treat as a queue - most recently played at the back of the queue
var playerStack = new List<string>(players);
//a list that we can modify
var gamesList = new List<MatchUp>(games);
while (gamesList.Count > 0)
{
//find a game for the top player on the stack
var player1 = playerStack.First();
var player2 = playerStack.Skip(1).First();
//the players are in the order of least recently played first
MatchUp matchUp = FindFirstAvailableGame(playerStack, gamesList);
//drop the players that just played to the back of the list
playerStack.Remove(matchUp.Player1);
playerStack.Remove(matchUp.Player2);
playerStack.Add(matchUp.Player1);
playerStack.Add(matchUp.Player2);
//remove that pairing
gamesList.Remove(matchUp);
//yield return matchUp; //optional way of doing this
results.Add(matchUp);
}
return results;
}
private static MatchUp FindFirstAvailableGame(List<string> players, List<MatchUp> gamesList)
{
for (int i = 0; i < players.Count - 1; i++)
{
for (int j = i + 1; j < players.Count; j++)
{
var game = gamesList.FirstOrDefault(g => g.Player1 == players[i] && g.Player2 == players[j] ||
g.Player2 == players[i] && g.Player1 == players[j]);
if (game != null) return game;
}
}
throw new Exception("Didn't find a game");
}
static void Main(string[] args)
{
var players = new List<string>(new []{"A","B","C","D","E"});
var allGames = new List<MatchUp>(PairPlayers(players));
Console.WriteLine("Unorganised");
foreach (var game in allGames)
{
Console.WriteLine(game);
}
Console.WriteLine("Organised");
foreach (var game in OrganiseGames(players, allGames))
{
Console.WriteLine(game);
}
Console.ReadLine();
}
}
}