如何在C编程中简化多个重复的if / else if语句

时间:2017-01-19 04:35:11

标签: c performance if-statement coordinates coding-efficiency

我目前制作的游戏需要很多if语句,以确定用户点击的位置并相应地执行操作。它检查用户是否单击指定的坐标。下面的代码工作得非常好,但是我很难想出一个有效的方法来做到这一点(不仅仅是这个代码,而是一般的代码)。

if((mx > 78) && (mx < 113) && (my > 157) && (my < 191)) ifff(0, 0, 78, 157, 113, 191);
else if((mx > 116) && (mx < 150) && (my > 157) && (my < 191)) ifff(1, 0, 116, 157, 150, 191);
else if((mx > 153) && (mx < 188) && (my > 157) && (my < 191)) ifff(2, 0, 153, 157, 188, 191);
else if((mx > 196) && (mx < 230) && (my > 157) && (my < 191)) ifff(3, 0, 196, 157, 230, 191);
else if((mx > 233) && (mx < 267) && (my > 157) && (my < 191)) ifff(4, 0, 233, 157, 267, 191);
else if((mx > 270) && (mx < 303) && (my > 157) && (my < 191)) ifff(5, 0, 270, 157, 303, 191);
else if((mx > 311) && (mx < 345) && (my > 157) && (my < 191)) ifff(6, 0, 311, 157, 345, 191);
else if((mx > 348) && (mx < 384) && (my > 157) && (my < 191)) ifff(7, 0, 348, 157, 384, 191);
else if((mx > 388) && (mx < 421) && (my > 157) && (my < 191)) ifff(8, 0, 388, 157, 421, 191);

else if((mx > 78) && (mx < 113) && (my > 194) && (my < 229)) ifff(0, 1, 78, 194, 113, 229);
else if((mx > 116) && (mx < 150) && (my > 194) && (my < 229)) ifff(1, 1, 116, 194, 150, 229);
else if((mx > 153) && (mx < 188) && (my > 194) && (my < 229)) ifff(2, 1, 153, 194, 188, 229);
else if((mx > 196) && (mx < 230) && (my > 194) && (my < 229)) ifff(3, 1, 196, 194, 230, 229);
else if((mx > 233) && (mx < 267) && (my > 194) && (my < 229)) ifff(4, 1, 233, 194, 267, 229);
else if((mx > 270) && (mx < 303) && (my > 194) && (my < 229)) ifff(5, 1, 270, 194, 303, 229);
else if((mx > 311) && (mx < 345) && (my > 194) && (my < 229)) ifff(6, 1, 311, 194, 345, 229);
else if((mx > 348) && (mx < 384) && (my > 194) && (my < 229)) ifff(7, 1, 348, 194, 384, 229);
else if((mx > 388) && (mx < 421) && (my > 194) && (my < 229)) ifff(8, 1, 388, 194, 421, 229);

else if((mx > 78) && (mx < 113) && (my > 231) && (my < 266)) ifff(0, 2, 78, 231, 113, 266);
else if((mx > 116) && (mx < 150) && (my > 231) && (my < 266)) ifff(1, 2, 116, 231, 150, 266);
else if((mx > 153) && (mx < 188) && (my > 231) && (my < 266)) ifff(2, 2, 153, 231, 188, 266);
else if((mx > 196) && (mx < 230) && (my > 231) && (my < 266)) ifff(3, 2, 196, 231, 230, 266);
else if((mx > 233) && (mx < 267) && (my > 231) && (my < 266)) ifff(4, 2, 233, 231, 267, 266);
else if((mx > 270) && (mx < 303) && (my > 231) && (my < 266)) ifff(5, 2, 270, 231, 303, 266);
else if((mx > 311) && (mx < 345) && (my > 231) && (my < 266)) ifff(6, 2, 311, 231, 345, 266);
else if((mx > 348) && (mx < 384) && (my > 231) && (my < 266)) ifff(7, 2, 348, 231, 384, 266);
else if((mx > 388) && (mx < 421) && (my > 231) && (my < 266)) ifff(8, 2, 388, 231, 421, 266);

else if((mx > 78) && (mx < 113) && (my > 231) && (my < 266)) ifff(0, 3, 78, 231, 113, 266);
else if((mx > 116) && (mx < 150) && (my > 231) && (my < 266)) ifff(1, 3, 116, 231, 150, 266);
else if((mx > 153) && (mx < 188) && (my > 231) && (my < 266)) ifff(2, 3, 153, 231, 188, 266);
else if((mx > 196) && (mx < 230) && (my > 231) && (my < 266)) ifff(3, 3, 196, 231, 230, 266);
else if((mx > 233) && (mx < 267) && (my > 231) && (my < 266)) ifff(4, 3, 233, 231, 267, 266);
else if((mx > 270) && (mx < 303) && (my > 231) && (my < 266)) ifff(5, 3, 270, 231, 303, 266);
else if((mx > 311) && (mx < 345) && (my > 231) && (my < 266)) ifff(6, 3, 311, 231, 345, 266);
else if((mx > 348) && (mx < 384) && (my > 231) && (my < 266)) ifff(7, 3, 348, 231, 384, 266);
else if((mx > 388) && (mx < 421) && (my > 231) && (my < 266)) ifff(8, 3, 388, 231, 421, 266);

4 个答案:

答案 0 :(得分:3)

基本思想是找到一种方法来表示代码中某些数据结构中每个行/块中的数据,然后创建这些数据结构的数组并循环遍历它们。

最简单的方法是创建一个数组,该数组将保存您想要的有关这些条件的数据。

例如,

[78, 113, 157, 191]   # represents first if statement

然后,您可以创建一个包含9个此类数组的数组,这些数组将代表您在上述每个部分中的9个条件。

然后,您可以创建一个包含四个这样的数组的数组,其中每个成员最终代表代码中的每个部分。

最后,你只需遍历所有这些内容,例如:

for (i=0; i<4; i++)
    for (j=0; j<9; j++)
        if (mx > my_map[i][j][0]) && (mx < my_map[i][j][1]) ...
            ifff(j, i, my_map[i][j][0], ....

你可以使用结构而不是数组,这将使上面的内容更容易阅读,但我不能举一个例子,因为你的代码不清楚不同的部分应该代表什么。

答案 1 :(得分:2)

为此,有interval trees之类的数据结构,请参阅Cormen一章或麻省理工学院关于此数据结构的算法课程。

答案 2 :(得分:1)

似乎是您的区间集中的某种结构。多次使用((mx > 78) && (mx < 113)) ...然后您可以在代码中反映该结构,例如:

if ((mx > 78) && (mx < 113)
    if (condition on my)
    else if (condition on my)
    ...
else if (condition on mx)
    if (condition on my)
    else if (condition on my)
    ...

当然,它会破坏阅读的规律性,但一切都有代价。你甚至可以分解更多(想法是测试任何条件一次):

    if (mx > 78)
        if (mx < 113)
            if (first condition on my)
               if (second condition on my)
    ...

答案 3 :(得分:1)

正如我在评论中指出的那样,您的第四个else if语句块正在遭受复制&#39; n&#39; paste-itis。它与第三个块具有相同的y范围(my > 231 && my < 266)。因此,它永远不会有任何用处,因为如果范围匹配,第三个块优先,如果不匹配,它只会浪费时间重复一系列失败的测试。

但是,你有一个相当清晰的结构,可以通过几个表,查找函数和对ifff()函数的单个调用来更好地表示,如下所示:

struct Range
{
    int lo;
    int hi;
    int key;
};

static const struct Range x_range[] =
{
    {  78, 113, 0 },
    { 116, 150, 1 },
    { 153, 188, 2 },
    { 196, 230, 3 },
    { 233, 267, 4 },
    { 270, 303, 5 },
    { 311, 345, 6 },
    { 348, 384, 7 },
    { 388, 421, 8 },
};
enum { NUM_X_RANGE = sizeof(x_range) / sizeof(x_range[0]) };

static const struct Range y_range[] =
{
    { 157, 191, 0 },
    { 194, 229, 1 },
    { 231, 266, 2 },
    { 268, 299, 3 },    /* Guessed range */
};
enum { NUM_Y_RANGE = sizeof(y_range) / sizeof(y_range[0]) };

static inline int range_lookup(int val, const struct Range *range, int num_ranges)
{
    for (int i = 0; i < num_ranges; i++)
    {
        if (val > range[i].lo && val < range[i].hi)
            return i;
    }
    return -1;
}

extern void ifff_range(int mx, int my);
extern void ifff(int xkey, int ykey, int xlo, int ylo, int xhi, int yhi);

void ifff_range(int mx, int my)
{
    int xr = range_lookup(mx, x_range, NUM_X_RANGE);
    int yr = range_lookup(my, y_range, NUM_Y_RANGE);
    if (xr != -1 && yr != -1)
        ifff(x_range[xr].key, y_range[yr].key,
             x_range[xr].lo,  y_range[yr].lo,
             x_range[xr].hi,  y_range[yr].hi);
}

在此数据中,结构中的键值与数组中行的索引相同,因此键可以从结构中删除。 查找失败的方法有很多种。例如,mx == 114my == 192将始终失败。