随机化if ... else语句的顺序。什么是最有效的方式?

时间:2013-12-11 02:51:37

标签: c++ if-statement code-organization statements

这样做的目的是使if语句的顶部不是底部的首选。我尝试为每个案例分配枚举值。然后选择一个从0到包含那些枚举元素的std::list myList大小的随机整数r。使用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);
    }
    } 

4 个答案:

答案 0 :(得分:0)

好消息,你可以让这个运行更快,使代码更短,更清晰,更容易移动...更不用说给你想要的行为了 - 一切都很简单:)

定义面向方向的列表:

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;
   }
}

一般的想法是你定义一个策略模式来确定某些东西是否有效。

然后,您可以设置一个列表,其中包含该策略模式的所有各种排列。

然后从随机位置开始遍历列表

上面的代码可能需要整理一下,因为我把它放在一起,它应该给你一些东西可以建立。

答案 1 :(得分: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委员会的工作。

答案 2 :(得分: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

但与第一种方法相比,性能仍然没有提高。但是代码现在更加优雅和灵活。

答案 3 :(得分:0)

您使用的是错误的解决方案。

这就是问题所在。

  

大多数人最终会面对同样的方向,我不喜欢。

解决方案是使用随机数来影响方向。不要使用随机数来影响代码生成。

使用随机数来影响代码生成存在以下问题:

  • 它会慢一点(正如你已经确定的那样)
  • 无论如何,编译器可以有效地重新排序语句(与源代码相比)。所以你最终还是要打击编译器,这不是一件好事。
  • 增加了复杂性,使程序更难理解,维护,调试等。


一个想法可以解决您的问题:

  1. 生成面向随机的方向。
  2. 如果该方向被阻挡,则选择随机旋转方向。
    • 然后旋转角色(在拾取的方向上),直到找到未阻挡的方向。