2014-09-19 2 views
0

У меня есть список private List<HeroStats> allHeroes;список случайных объектов из другого списка C#

и список private List<Team> allTeams;

После того как я заполнить мой список «allHeroes» с героями, я хочу, чтобы создать команду из 5 случайных героев, используя этот метод:

public Team createTeam() 
{ 
    int index=0; 
    Team t = new Team(); 
    Random rnd = new Random(); 
    int cap = allHeroes.Count; 
    while (t.count() < 5) 
    { 
     index = rnd.Next(0, cap); 
     t.Add(allHeroes.ElementAt(index)); 
    } 
    return t; 
} 


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

public List<HeroStats> print() 
{ 
    StringBuilder sb = new StringBuilder(); 
    List<HeroStats> l = new List<HeroStats>(); 
    foreach (HeroStats h in team) 
    { 
     sb.AppendLine(h.HeroName); 
     l.Add(h); 
    } 
    Console.WriteLine(sb.ToString()); 
    return l; 
} 

Что необходимо распечатать имя героев в команде.

Почему я получаю ту же команду, если создаю много?



Чтобы создать несколько команд я использую:

Team a = new Team(); 
      for (int i = 0; i < 2000; i++) 
      { 
       a = createTeam(); 
       allTeams.Add(a); 

     } 
+1

Вы должны объявить свое случайное статически на уровне класса. –

+1

Кроме того, 'cap' является [эксклюзивным максимумом] (http://www.dotnetperls.com/random), поэтому вы должны установить его на allHeroes.Count + 1 –

+0

Или просто дать классу Random класс: public Random a = new Random (DateTime.Now.Ticks.GetHashCode()); – SeraphimFoA

ответ

2

Это создает ту же команду, так как экземпляр Random создается в методе, который вызывает такое же семя, если вы звоните createTeam очень быстро (default Random constructor использует текущее время в качестве семян). Вы можете избежать этого, либо путем передачи Random к методу или с помощью поля:

public Team createTeam(Random rnd) // as an aside, you should call it CreateRandomTeam 
{ 
    int index=0; 
    Team t = new Team(); 
    int cap = allHeroes.Count; 
    while (t.count() < 5) 
    { 
     index = rnd.Next(0, cap); 
     t.Add(allHeroes.ElementAt(index)); 
    } 
    return t; 
} 

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

Например, с вашей петлей:

Random rnd = new Random(); 
Team a = new Team(); 
for (int i = 0; i < 2000; i++) 
{ 
    a = createTeam(rnd); 
    allTeams.Add(a); 
} 

MSDN также упоминает об этом в разделе примечаний:

по умолчанию семян Значение происходит от системных часов и имеет разрешение конечного . В результате разных случайных объектов, которые создаются в , замыкаются на вызов вызовом конструктора по умолчанию, будут иметь одинаковые начальные значения по умолчанию и, следовательно, будут производить одинаковые наборы случайных чисел. Эту проблему можно избежать, используя один случайный объект для генерации всех случайных чисел.Вы также можете работать вокруг его, изменяя начальное значение, возвращенное системными часами, а затем явно обеспечивая это новое значение семян в случайном порядке (Int32) конструктор

0

Если вы создаете много Random экземпляров примерно в то же время, они могут генерировать одни и те же цифры. Вместо этого создайте один Random в другом месте и вызовите его метод Next из вашего алгоритма.

1

Вы должны иметь

Random rnd = new Random(); 

Вне

public Team createTeam() 
{ 

} 

Может разобрать в РНД в качестве параметра.

1

С documentation из Random

Начальное значение по умолчанию выводится из системных часов и имеет конечное разрешение. В результате различные объекты Random, которые создаются с тесной последовательностью при вызове конструктора по умолчанию, будут иметь одинаковые начальные значения по умолчанию и, следовательно, будут создавать одинаковые наборы случайных чисел.

Если вы звоните createTeam() в тугой петлей, чтобы создавать свои случайные команды, вы будете в конечном итоге с тем же набором случайных чисел из-за того, что ваши экземпляры Random будут создавать так близко друг к другу и с одно и то же семя.

Возможное решение - вынуть объект типа Random и сделать его полем уровня класса.

public static class RandomTeamCreator 
{ 
    private static readonly Random _random = new Random(); 
    public Team CreateTeam() 
    { 
     // create team using _random 
    } 
} 
1

Почему я получаю ту же команду, если я произвожу много?

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

Я хотел бы добавить параметр "семени" в createTeam:

public Team createTeam(int seed) 
{ 
    int index=0; 
    Team t = new Team(); 
    Random rnd = new Random(seed); 
    int cap = allHeroes.Count; 
    while (t.count() < 5) 
    { 

     index = rnd.Next(0, cap); 
     t.Add(allHeroes.ElementAt(index)); 
    } 
    return t; 
} 

И затем использовать другойRandom вне й ELOOP для создания семян:

for(int 1 = 0; i < 10; i++) 
{ 
    Random r = new Random(0); 
    int seed = r.Next(); 
    createTeam(int seed); 
} 

Если вы хотите чтобы сохранить оригинальную подпись, просто добавьте перегрузку:

public Team createTeam() 
{ 
    return createTeam(new Random().Next()); 
} 

SIDE ПРИМЕЧАНИЕ

Вы _probably хотите «перетасовать» команду героев, а не «случайный», так как с «случайным» вы могли получить тот же самый герой дважды. Если это так, просто используйте «порядок по» со случайным порядком:

public Team createTeam(int seed) 
{ 
    Random rnd = new Random(seed); 

    Team t = new Team(); 

    var shuffled = allHeroes.OrderBy(rnd.Next()).Take(5); 
    foreach(var hero in shuffled) 
     t.Add(hero); 

    return t; 
} 
Смежные вопросы