Подбор игроков: выберите две случайные команды и случайным образом выберите победителя

#c# #random #duplicates

Вопрос:

Краткое описание: Случайным образом выберите два элемента из массива, а затем удалите их из массива, а затем случайным образом выберите один элемент из двух уже случайно выбранных элементов.

Я знаю, что об этом, вероятно, спрашивали раньше, но все ответы, которые я мог найти, я не знал, как применить к своему коду.

Вот мой код:

 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]);
 

Как я могу сделать так, чтобы две команды всегда были разными, и чтобы я мог провести 2-й раунд, в котором будут еще две разные команды?

Еще одна вещь, которую мне нужно сделать, — это сделать так, чтобы, когда две команды будут выбраны для раунда (допустим, это команда 3 и команда 7), случайным образом выбрать одну из этих двух команд, чтобы я мог определить победителя. Я перепробовал кучу вещей, и ни одна из них не сработала, в основном мне нужна помощь с первой проблемой, но если кто-нибудь может помочь и со второй, я был бы признателен.

Комментарии:

1. В качестве примечания, не должно быть необходимости в двух Random экземплярах. Одного Random должно быть достаточно для всех случайных чисел, которые вы хотите сгенерировать. Что касается основной проблемы, не могли бы вы включить в вопрос пример желаемого результата программы?

2. Простой выход-просто чтобы сравнить результат с предыдущими результатами, если он находится слишком близко от предыдущего результата, то просто попробуйте это опять же классический не получите следующий результат}в то время как(результат != предыдущее); в противном случае, можно исключить одну или обе команды от массив до рандомизации, это может быть достигнуто с помощью простых запросов LINQ.

3. Если вы случайным образом выбираете два элемента из одного массива (при условии равномерного распределения), нет необходимости затем рандомизировать порядок этих двух элементов. Вы с такой же вероятностью выбрали бы b тогда, a как a и тогда b .

Ответ №1:

Для того, чтобы реализовать его, нам действительно нужно отслеживать раунд, в который продвинулась команда.

С 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 и т. Д.).

Ответ №2:

Один из методов состоит в том, чтобы создать копию массива, думайте об этом так, как если бы вы написали каждое из имен на листе бумаги и положили их в шляпу, мы назовем это 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 , просто повторно используйте существующий.

Я не большой поклонник этого синтаксиса, подобную логику часто легче понять, когда ссылки на объекты используются вместо того, чтобы хранить массив индексов в другом массиве, однако это близко приближает проблему OPs.

Одно выполнение этого имеет следующий результат:

 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]
 

Ни в коем случае нам не нужно было манипулировать исходной коллекцией teams , кроме как добавлять 9-ю 😉
Таким образом, просто рандомизируя список адресов исходных ссылок, мы можем получить рандомизированный вывод с использованием детерминированной логики.