Порядок рандомизации операторов if … else. Какой самый эффективный способ?

Цель этого состоит в том, чтобы верхняя часть операторов if не была предпочтительнее нижней. Я пытался присвоить значения enum для каждого случая. Затем выберите случайное целое число от 0 до размера std::list myList содержащий эти элементы перечисления. Значение enum находится с помощью it = std::next (myList, r), Тогда, если оператор if, соответствующий этому значению перечисления false, затем myList.erase (it)и повторите процесс с новым уменьшением myList, Это работает, и все кажется хорошо рандомизированным. Но это, к сожалению, гораздо медленнее, чем когда я использовал оригинал if-else заявления. Есть предложения по более быстрому способу?
Вот фрагмент моего кода. Там толпа девушек. Каждый парень выберет девушку, а затем выберет направление, чтобы танцевать с выбранной девушкой. Но не все направления лицом к лицу возможны, если кто-то стоит в том месте, в котором он хочет стоять, чтобы получить желаемое направление движения. Без рандомизации if-else Заявления, большинство парней в конечном итоге окажутся в том же направлении, что мне не нравится.

std::list<FacingDirection> guyFacingDirections = {Positive_x, Negative_x, Positive_y, Negative_y, Positive_xPositive_y, Positive_xNegative_y, Negative_xPositive_y, Negative_xNegative_y};
while (true)    {
const int r = rand() % guyFacingDirections.size();
std::list<FacingDirection>::iterator it = std::next(guyFacingDirections.begin(), r);
const FacingDirection facingDirectionChoice = *it;
if (facingDirectionChoice == Positive_x)  // I decided that using switch (facingDirectionChoice) {case Positive_x: if (... was too clumsy in code and probably no more efficient.
{
if (mainArea.locationAvailable (xChoice - 1, yChoice, zChoice))
{guy->movesToNewLocation (xChoice - 1, yChoice, zChoice);  break;}
else
guyFacingDirections.erase (it);  // more efficient than 'guyFacingDirections.remove (Positive_x);'
}
else if (facingDirectionChoice == Negative_x)
{
if (mainArea.locationAvailable (xChoice + 1, yChoice, zChoice))
{guy->movesToNewLocation (xChoice + 1, yChoice, zChoice);  break;}
else
guyFacingDirections.erase (it);
}
else if (facingDirectionChoice == Positive_y)
{
if (mainArea.locationAvailable (xChoice, yChoice - 1, zChoice))
{guy->movesToNewLocation (xChoice, yChoice - 1, zChoice);  break;}
else
guyFacingDirections.erase (it);
}
else if (facingDirectionChoice == Negative_y)
{
if (mainArea.locationAvailable (xChoice, yChoice + 1, zChoice))
{guy->movesToNewLocation (xChoice, yChoice + 1, zChoice);  break;}
else
guyFacingDirections.erase (it);
}
else if (facingDirectionChoice == Positive_xPositive_y)
{
if (mainArea.locationAvailable (xChoice - 1, yChoice - 1, zChoice))
{guy->movesToNewLocation (xChoice - 1, yChoice - 1, zChoice);  break;}
else
guyFacingDirections.erase (it);
}
else if (facingDirectionChoice == Positive_xNegative_y)
{
if (mainArea.locationAvailable (xChoice - 1, yChoice + 1, zChoice))
{guy->movesToNewLocation (xChoice - 1, yChoice + 1, zChoice);  break;}
else
guyFacingDirections.erase (it);
}
else if (facingDirectionChoice == Negative_xPositive_y)
{
if (mainArea.locationAvailable (xChoice + 1, yChoice - 1, zChoice))
{guy->movesToNewLocation (xChoice + 1, yChoice - 1, zChoice);  break;}
else
guyFacingDirections.erase (it);
}
else if (facingDirectionChoice == Negative_xNegative_y)
{
if (mainArea.locationAvailable (xChoice + 1, yChoice + 1, zChoice))
{guy->movesToNewLocation (xChoice + 1, yChoice + 1, zChoice);  break;}
else
guyFacingDirections.erase (it);
}
}

1

Решение

Хорошая новость: вы можете сделать это быстрее, сделать код намного короче, намного яснее и проще в перемещении … не говоря уже о том, чтобы получить желаемое поведение — и все одним простым движением 🙂

Определите список направлений:

class HandleFacingDirection {

final int x;
final int y;

HandleFacingDirection(int x, int y) {
this.x = x;
this.y = y;
}

public boolean canFace(int xChoice, int yChoice, int zChoice) {
if (mainArea.locationAvailable (xChoice + x, yChoice + y, zChoice)) {
guy->movesToNewLocation (xChoice + 1, yChoice, zChoice);
return true;
}
return false;
}
}

Затем определите массив:

HandleFacingDirection[] directionHandlers = new HandleFacingDirections[] {
new HandleFacingDirection(1, 0),
new HandleFacingDirection(-1, 0),
new HandleFacingDirection(0, 1),
new HandleFacingDirection(0, -1)
}

Определите генератор случайных чисел где-нибудь:

Random random = new Random();

Теперь ваш код для обработки просто становится:

int offset = random.nextRandomInt(directionHandlers.length);
for (int i=0;i<directionHandlers.length;i++) {
int index = i+offset;
if (index > directionHandlers.length)
index -= directionHandlers.length;
if (directionHandlers[index].canFace(xChoice, yChoice, zChoice)) {
break;
}
}

Общая идея заключается в том, что вы определяете шаблон Стратегии, чтобы определить, является ли что-то действительным.

Затем вы создаете список, содержащий все различные варианты этого шаблона стратегии.

Затем вы перебираете список начиная со случайной позиции.

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

0

Другие решения

Да, я попробовал следующее:

struct Direction {
int delta_x;
int delta_y;
// FacingDirection dir;  // if this information is also desired
};
static std::vector<Direction> directions = { {1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1} }; // static so that it only needs be initialized once
std::random_shuffle (std::begin (directions), std::end (directions));
//FacingDirection chosenDirection;  // use this if this information is needed (currently it is not)
for (const Direction& d: directions)  // Range-based for-loop MIGHT give faster performance.
{
const int x = xChoice + d.delta_x;
const int y = yChoice + d.delta_y;
if (mainArea.locationAvailable (x, y, zChoice))
{
guy->movesToNewLocation (x, y, zChoice);
//chosenDirection = d.dir;  // currently not needed for my program
break;
}
}

Спасибо JLBorges за это предложение. Оказывается, он НЕ работает быстрее, чем мой оригинальный метод, но он решает проблему обработки произвольного большого количества случаев.

Похоже, что в настоящее время нет способа рандомизировать порядок операторов if-else, в то время как производительность практически совпадает с неслучайным набором операторов if-else. Комитет C ++ 14 должен работать над этим.

0

Последняя попытка объединить идеи JLBorges и TimB:

struct Direction {
int delta_x;
int delta_y;
// FacingDirection dir;  // if this information is also desired
bool canFace (Guy* guy, int x, int y, int z) const {
if (guy->LocationSituated()->locationAvailable (x + delta_x, y + delta_y, z))
{
guy->movesToNewLocation (x + delta_x, y + delta_y, z);
return true;  // return std::make_pair (true, dir); if FacingDirection information is needed (currently it is not)
}
return false;
}
};
static std::vector<Direction> directions = { {1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1} }; // static so initialization only once
std::random_shuffle (std::begin (directions), std::end (directions));
for (const Direction& d: directions)  // Range-based for-loop MIGHT give faster performance
if (d.canFace (guy, xChoice, yChoice, zChoice))
break;  // (xChoice, yChoice, zChoice) is the position of the girl he wants to dance with

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

0

Вы используете неправильное решение.

Это проблема.

большинство парней окажутся в том же направлении, что мне не нравится.

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

Использование случайных чисел для влияния на генерацию кода имеет следующие проблемы:

  • Это будет медленнее (как вы уже определили)
  • В любом случае компилятор может эффективно изменить порядок операторов (по сравнению с вашим исходным кодом). Таким образом, вы в конечном итоге боретесь с компилятором, что не очень хорошая вещь.
  • Добавляет сложности, усложняя понимание, сопровождение, отладку и т. Д.

Одна идея исправить вашу проблему:

  1. Генерация случайного направления лицом.
  2. Если это направление заблокировано, выберите случайное направление вращения.
    • Затем вращайте персонажа (в выбранном направлении), пока он не найдет разблокированную ориентацию.
0
По вопросам рекламы [email protected]