Неэффективный массив Shuffler.
Вопрос
Я пытаюсь перетасовать массив, но то, как я делаю, это работает, только примерно каждый пятый раз. Я бы очень признателен, если бы кто-то мог объяснить, почему он не работает должным образом и, возможно, предложит твик.
private Button[] scrambleBoard(Button[] buttons)
{
for (int x = 100 * buttons.Count(); x > 0; x--)
{
Random rand = new Random();
int first = rand.Next(buttons.Count());
int second = rand.Next(buttons.Count());
Button temp = buttons[first];
buttons[first] = buttons[second];
buttons[second] = temp;
}
return buttons;
}
Решение
Переместите следующую линию за пределами петли:
Random rand = new Random();
Семя по умолчанию, используемое System.Random
основан на Environment.TickCount
. Отказ В тесной петле клещница может не изменяться между последовательными итерациями, поэтому он может в конечном итоге использовать с тем же сеемкой снова и снова. Следовательно, цикл будет многократно поменять такой же два элемента до изменения тика-подсчета (он не может сделать это до завершения петли). Чтобы убедиться, что это проблема, вы можете попробовать добавить Thread.Sleep(100)
или аналогично внутри петли; Вы должны быть в состоянии увидеть шаффл, работающую правильно (хотя и очень медленно).
Вы также должны отметить, что Техника, которую вы используете Развернуть массив пристрастный; Не каждая перестановка одинаково вероятно. Возможно, вы захотите использовать алгоритм спретра, который, как известно, является беспристрастным, таким как Fisher-Yates Shuffle.
В качестве альтернативы вы можете использовать действительно простую технику для перемещения. Это немного неэффективно, но беспристрастный:
var rand = new Random();
return buttons.OrderBy(button => rand.Next()).ToArray();
Другие советы
Проблема в том, что вы создаете случайную () объект в каждой итерации вашей петли. В качестве случайного объекта используются семену во время инициализации, вы обнаружите, что большинство значений будут идентичны и не случайно.
Вы можете решить проблему, объявляя случайном классе как статическое снаружи корпуса метода.
private static Random rand = new Random();
private Button[] scrambleBoard(Button[] buttons)
{
for (int x = 100 * buttons.Count(); x > 0; x--)
{
int first = rand.Next(buttons.Count());
int second = rand.Next(buttons.Count());
Button temp = buttons[first];
buttons[first] = buttons[second];
buttons[second] = temp;
}
return buttons;
}
Ваш вопрос ответил, но я подумал, что поделюсь приятным маленьким трюком для перетаскивания коллекции, используя LINQ и GUID. Это создает случайно заказанный список с приятным распространением значений.
private Button[] scrambleBoard(Button[] buttons)
{
return buttons.OrderBy(b => Guid.NewGuid()).ToArray();
}