配对:随机挑选两支队伍,随机选出获胜者



简要描述:从一个数组中随机选择两个项目,然后将它们从数组中删除,然后从两个已经随机选择的项目中随机选择一个项目。

我知道以前可能有人问过这个问题,但我能找到的所有答案都不知道如何应用于我的代码。

这是我的代码:

string[] teams = { "Team 1", "Team 2", "Team 3", "Team 4", "Team 5", "Team 6",
"Team 7", "Team 8" };
Console.WriteLine("The available teams are: ");
for (int i = 0; i < teams.Length; i++)
{
Console.WriteLine(teams[i]);
}
Random rnd1 = new Random();
int r1 = rnd1.Next(teams.Length);
Random rnd2 = new Random();
int r2 = rnd2.Next(teams.Length);
Console.WriteLine("Round 1: " + teams[r1] + " vs " + teams[r2]);

我如何才能让这两支球队永远不同,让我能够进行第二轮比赛,这将是另外两支不同的球队?

我需要做的另一件事是,当两支球队(假设是第三队和第七队(被选中进行一轮比赛时,从这两支球队中随机选择,这样我就可以决定获胜者。我尝试了很多方法,但都没有奏效,我主要需要帮助解决第一个问题,但如果有人也能帮助解决第二个问题,我将不胜感激。

为了实现它,我们真的需要跟踪团队已经晋级的回合。

对于8支球队,最多可以进行3轮比赛。

在做任何事情之前,我们可以打乱我们的球队名单,然后将他们配对,以便进行他们的比赛。获胜的队伍将晋级下一轮。

第一件事是定义我们的班级团队:

public class Team
{
public string Name { get; set; }
public int Round { get; set; }
}

然后我们要做的就是创建两个嵌套的循环。

外循环模拟正在进行的回合,而内循环模拟两支球队之间的当前比赛,决定获胜者。

综合起来我们有:

public class Team
{
public string Name { get; set; }
public int Round { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Team> teams = new List<Team>
{
new Team
{
Name = "Team 1",
Round = 0
},
new Team
{
Name = "Team 2",
Round = 0
},
new Team
{
Name = "Team 3",
Round = 0
},
new Team
{
Name = "Team 4",
Round = 0
},
new Team
{
Name = "Team 5",
Round = 0
},
new Team
{
Name = "Team 6",
Round = 0
},
new Team
{
Name = "Team 7",
Round = 0
},
new Team
{
Name = "Team 8",
Round = 0
}
};
for (int j = 0; j < teams.Count / (teams.Count / 4); j++)
{
//select current round and shuffles the teams
Random rng = new Random();
var currentPlayingTeams = teams.Where(x => x.Round == j).Select(c => c).ToList().OrderBy(x => rng.Next()).ToList();
if (currentPlayingTeams.Count > 1)
{
Console.WriteLine($"---------------- Round {j + 1}----------------------");
for (int i = 0; i < currentPlayingTeams.Count; i += 2)
{
var currentMatch = currentPlayingTeams.GetRange(i, 2);
Console.WriteLine($"{currentMatch[0].Name} VS {currentMatch[1].Name}");
System.Threading.Thread.Sleep(1000);
Random ran = new Random();
var matchWinner = ran.Next(0, 2);
Console.WriteLine($"{currentMatch[matchWinner].Name} Won");
System.Threading.Thread.Sleep(1000);
teams.FirstOrDefault(x => x.Name == currentMatch[matchWinner].Name).Round++;
}
}
}
var winner = teams.OrderByDescending(v => v.Round).First();
Console.WriteLine("---------------- Result----------------------");
Console.WriteLine($"The winning team is {winner.Name}");
Console.ReadLine();
}
}

既然我们已经洗牌了,我们就可以选择前2名,让他们上场。

实现要求团队的数量是2n的幂(4、8、16、32等(。

一种方法是创建数组的副本,将其视为将每个名称放在一张纸上并放入一顶帽子中,我们将其称为pool。现在,当您从pool中随机选择团队时,请在再次选择之前将该团队从pool中删除:

Random rand = new Random();
string[] teams = { "Team 1", "Team 2", "Team 3", "Team 4", "Team 5", "Team 6", "Team 7", "Team 8" };
Console.WriteLine("The available teams are: ");
for (int i = 0; i < teams.Length; i++)
{
Console.WriteLine(teams[i]);
}
List<int> pool = new List<int>(Enumerable.Range(0, teams.Length));
int round = 0;
while(pool.Any())
{
round++;
int index = rand.Next(0, pool.Count);
int r1 = pool[index];
pool.RemoveAt(index);
index = rand.Next(0, pool.Count);
int r2 = pool[index];
pool.RemoveAt(index);
Console.Write($"Round {round}: {teams[r1]} vs {teams[r2]}");
int winner = rand.Next(0, 2) == 1 ? r1 : r2;
Console.WriteLine($" - Winner: {teams[winner]}");
}

如注释中所述,不需要创建Random的新实例,只需重用现有实例即可。

我不太喜欢这种语法,当使用对象引用而不是将一个索引数组保留到另一个数组中时,像这样的逻辑通常更容易理解,然而这与OP的问题非常接近。

其中一个执行具有以下输出:

The available teams are:
Team 1
Team 2
Team 3
Team 4
Team 5
Team 6
Team 7
Team 8
Round 1: Team 5 vs Team 4 - Winner: Team 4
Round 2: Team 6 vs Team 1 - Winner: Team 6
Round 3: Team 3 vs Team 2 - Winner: Team 3
Round 4: Team 8 vs Team 7 - Winner: Team 8

从帽子里取名字的场景中通常我们要做的是把名字放在帽子里,把它们打乱,然后按顺序取出来。因此,我们实际上可以通过对pool进行排序而不是删除随机索引中的项来简化逻辑,一旦对集合进行了一次排序,那么结果就已经足够随机了。

List<int> pool = new List<int>(Enumerable.Range(0, teams.Length).OrderBy(x => rand.Next()));
int round = 0;
while (pool.Any())
{
round++;
int r1 = pool[0];
int r2 = pool[1];
// remove the entries before the next round
pool.RemoveAt(0);
pool.RemoveAt(0); // previous remove has shifted the array
Console.Write($"Round {round}: {teams[r1]} vs {teams[r2]}");
// still randomly select a winner from the two selected
int winner = rand.Next(0, 2) == 1 ? r1 : r2;
Console.WriteLine($" - Winner: {teams[winner]}");
}

这是一个细微的区别,但随机排序数组可以让你编写更具确定性的代码,而更可预测的代码更容易调试,结果仍然是随机的,事实上,现在我们不必从池中删除项目,我们可以简单地枚举池数组:

int [] pool = Enumerable.Range(0, teams.Length).OrderBy(x => rand.Next()).ToArray();
for (int index = 0, round = 1; index < pool.Length; index += 2, round ++)
{
int r1 = pool[index];
int r2 = pool[index + 1];
Console.Write($"Round {round}: {teams[r1]} vs {teams[r2]}");
// still randomly select a winner from the two selected
int winner = rand.Next(0, 2) == 1 ? r1 : r2;
Console.WriteLine($" - Winner: {teams[winner]}");
}

如果输入团队可能是奇数,这是可能发生的,只需在那里检查一下,然后给最后一个团队一个再见

var t = teams.ToList();
t.Add("Team 9");
teams = t.ToArray();
// now that there is an odd number of teams...
int[] p = Enumerable.Range(0, teams.Length).OrderBy(x => rand.Next()).ToArray();
for (int index = 0, round = 1; index < p.Length; index += 2, round ++)
{
if (p.Length > index + 1)
{
int r1 = p[index];
int r2 = p[index + 1];
Console.Write($"Round {round}: {teams[r1]} vs {teams[r2]}");
// still randomly select a winner from the two selected
int winner = rand.Next(0, 2) == 1 ? r1 : r2;
Console.WriteLine($" - Winner: {teams[winner]}");
}
else
{
int rb = p[index];
Console.Write($"Round {round}: {teams[rb]} *** bye ***");
}
}

上述输出为:

Round 1: Team 4 vs Team 2 - Winner: Team 4
Round 2: Team 5 vs Team 3 - Winner: Team 3
Round 3: Team 8 vs Team 1 - Winner: Team 1
Round 4: team 9 vs Team 6 - Winner: team 9
Round 5: Team 7 *** bye ***

对于之前的执行,pool具有以下内容:

[4,2,5,3,8,1,9,6,7]

除了添加第9个集合外,我们在任何时候都不需要操作teams的原始集合;(因此,通过简单地随机化原始引用的地址列表,我们可以使用确定性逻辑实现随机输出。

最新更新