Цель этого состоит в том, чтобы верхняя часть операторов 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);
}
}
Хорошая новость: вы можете сделать это быстрее, сделать код намного короче, намного яснее и проще в перемещении … не говоря уже о том, чтобы получить желаемое поведение — и все одним простым движением 🙂
Определите список направлений:
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;
}
}
Общая идея заключается в том, что вы определяете шаблон Стратегии, чтобы определить, является ли что-то действительным.
Затем вы создаете список, содержащий все различные варианты этого шаблона стратегии.
Затем вы перебираете список начиная со случайной позиции.
Приведенный выше код может потребовать некоторой корректировки, так как я просто собрал его вместе, он должен дать вам кое-что для дальнейшего развития.
Да, я попробовал следующее:
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 должен работать над этим.
Последняя попытка объединить идеи 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
Но по-прежнему нет улучшения производительности по сравнению с моим первым методом. Но код теперь намного элегантнее и гибче.
Вы используете неправильное решение.
Это проблема.
большинство парней окажутся в том же направлении, что мне не нравится.
Решение состоит в том, чтобы использовать случайные числа, чтобы влиять на направление. Не используйте случайные числа, чтобы повлиять на генерацию кода.
Использование случайных чисел для влияния на генерацию кода имеет следующие проблемы:
Одна идея исправить вашу проблему: