简体   繁体   English

如何在C ++中更有效地使用?

[英]How to use while more efficiently in C++?

I am trying to code 2048 game in C++, and I created some functions to add a new random number in a random place after detecting user presses the arrows to play. 我试图用C ++编写2048游戏,我创建了一些函数来检测用户按下箭头后在随机位置添加新的随机数。 Those functions are about to find a place where no number has taken and then place the new number. 这些功能将查找没有数字的位置,然后放置新数字。 I tried to ways to do this. 我试图做到这一点。 One is kind of silly which is used a lot of cases, and the other one is just use while which works slow when I am running this game. 一种是在很多情况下都使用的愚蠢方式,另一种只是在我运行此游戏时工作缓慢时使用。 I am new to C++. 我是C ++的新手。 I hope someone can help me find a better solution. 我希望有人可以帮助我找到更好的解决方案。 And here are those code: 这是这些代码:

bool add_new_number_when_up()
{
    srand(time(NULL));
    int n = rand() % 2 + 1;
    int newnumber = pow(2, n);
    while(true) {
        if(check_up_move() == 1) {
            loop:
            int a = rand() % 8;
            switch(a) {
            case 0:
                if(grid[2][0] == 0) {
                    grid[2][0] = newnumber;
                    return false;
                }
                else {
                    goto loop;
                }
                break;
            case 1:
                if(grid[2][1] == 0) {
                    grid[2][1] = newnumber;
                    return false;
                }
                else {
                    goto loop;
                }
                break;
            case 2:
                if(grid[2][2] == 0) {
                    grid[2][2] = newnumber;
                    return false;
                }
                else {
                    goto loop;
                }
                break;
            case 3:
                if(grid[2][3] == 0) {
                    grid[2][3] = newnumber;
                    return false;
                }
                else {
                    goto loop;
                }
                break;
            case 4:
                if(grid[3][0] == 0) {
                    grid[3][0] = newnumber;
                    return false;
                }
                else {
                    goto loop;
                }
                break;
            case 5:
                if(grid[3][1] == 0) {
                    grid[3][1] = newnumber;
                    return false;
                }
                else {
                    goto loop;
                }
                break;
            case 6:
                if(grid[3][2] == 0) {
                    grid[3][2] = newnumber;
                    return false;
                }
                else {
                    goto loop;
                }
                break;
            case 7:
                if(grid[3][3] == 0) {
                    grid[3][3] = newnumber;
                    return false;
                }
                else {
                    goto loop;
                }
                break;
            }
        }
        else {
            return false;
        }
    }
}

And this is the other one: 这是另一个:

void test_if_zero(int row, int col) 
{
    srand(time(NULL));
    int n = rand() % 2 + 1;
    int newnumber = pow(2, n);
    if(grid[row][col] == 0) {
        grid[row][col] = newnumber;
    }
}

int check_empty()
{
    int flag = 0; 
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 4; j++) {
            if(grid[i][j] == 0) {
                flag = 1;
                return flag;
            }
        }
    }
}

bool add_new_number(int num)
{
    Loop:
    int row, col;
    srand(time(NULL));
    switch(num) {
    case 1: //up
        row = rand() % 2 + 2;
        col = rand() % 4;
        break;
    case 2: //down
        row = rand() % 2;
        col = rand() % 4;
        break;
    case 3: //left
        row = rand() % 4;
        col = rand() % 2 + 2;
        break;
    case 4: //right
        row = rand() % 4;
        col = rand() % 2;
        break;
    }
    while(true) {
        if(check_empty() == 1) {
            if(grid[row][col] == 0) {
                test_if_zero(row, col);
                return false;
            }
            else {
                goto Loop;
            }
        }
        else {
            break;
        }
    }
}

Almost 50 years have passed since professor Edsger W. Dijkstra wrote his paper "Go To Statement Considered Harmful" ( Communications of the ACM 11, 3, March 1968, p. 147-148.) and still unjustified uses of that construct can be found. 自Edsger W. Dijkstra教授撰写论文“发表声明被认为有害”以来已经过去了近50年( ACM通讯11,3 ,1968年3月,第147-148页),但仍然可以找到对该结构的不合理使用。 。

OP's first snippet can be summerised as: OP的第一个摘要可以总结为:

bool add_new_number_when_up()
{
    // ...
    while(true) {
        if( /* some unexplained condition */ ) {
            loop:                    // <- "loop" start
            int a = rand() % 8;
            switch(a) {
            case 0:
                if( /* something */ ) {
                    // ...
                    return false;
                }
                else {
                    goto loop;      // <- "loop" end
                }
                break;              // never reached...
            // many other cases...
            }
        }
        else {
            return false;
        }
    }
}

Which, besides the lack of any return true , could be (but really should not) rewritten as 除了没有return true ,还可以(但实际上不应)重写为

bool add_new_number_when_up()
{
    // ...
    while(true) {
        if( /* some unexplained condition */ ) {
            while(true) {                    // <- nested loop!
                int a = rand() % 8;
                switch(a) {
                case 0:
                    if( /* something */ ) {
                        // ...
                        return false;        // true?
                    }
                    break;                   // <- restart the loop...
                // many other cases...
                }
            }            
        }
        else {
            return false;
        }
    }
}

Writing an infinite loop as loop: ... goto loop; 将无限循环编写为loop: ... goto loop; instead of while(1) {...} doesn't make it magically faster, but it can surely obfuscate your code and it's more error prone. 而不是while(1) {...}并没有使它神奇地更快,但是它肯定会混淆您的代码,并且更容易出错。

The second snippet is even worse: 第二个片段更加糟糕:

bool add_new_number(int num)
{
    Loop:                      // <- what kind of loop is this?
    // some expansive function which shouldn't be here...
    // ... 
    while(true) {
        if( /* call to another relatively expansive function */ ) {
            if( /* some condition */ ) {
                // call to another expansive function...
                return false;
            }
            else {
                goto Loop;          // <- end of loop?
            }
        }
        else {
            break;
        }
    }
}           // <- a return statement is missing!

The OP complains about the slowness of this code, which is unsurprising, given the overall design and the functions involved. 考虑到总体设计和所涉及的功能,OP抱怨该代码的缓慢性,这不足为奇。

For example, there are multiple calls to srand , which are not only expansive, but also unnecessary as one call in the entire program, to seed the pseudo random number generator, is enough. 例如,存在对srand多次调用,这些调用不仅是扩展的,而且是不必要的,因为在整个程序中只有一个调用可以为伪随机数生成器提供种子。 The same would hold even for the "modern" <random> generators, like std::random_device and std::mt19937 . 即使对于“现代” <random>生成器也是如此,例如std::random_devicestd::mt19937

Making any kind of micro optimization at this point is useless, though. 但是,此时进行任何微优化都是没有用的。 It is far better to figure out a completely different algorithm. 最好找出完全不同的算法。

Those functions are about to find a place where no number has taken and then place the new number. 这些功能将查找没有数字的位置,然后放置新数字。

My suggestion is to firstly determine which cells of the grid are empty. 我的建议是首先确定网格中的哪些单元格为空。 Just traverse half of the grid (which part, depends on the direction passed to the function) and add the empty ones (or their indeces) to a list (could be an array...) of candidates. 只需遍历网格的一半(哪一部分取决于传递给函数的方向),然后将空的(或其索引)添加到候选列表(可以是数组...)。 There are 8 at most of those, it is a very small domain, it has to be a fast loop (or nested loops). 其中最多有8个,这是一个非常小的域,必须是一个快速循环(或嵌套循环)。

If there aren't any valid candidates, then return false, no number is added. 如果没有有效的候选者,则返回false,不添加任何数字。

Otherwise, you can extract a random index between 0 and the number of candidates - 1 to choose between them the cell to be updated. 否则,您可以提取介于0和候选数之间的随机索引-1,以在它们之间选择要更新的单元格。 You don't need to check again if it is empty, thanks to the previous step, just extract a number between 1 and 2 to use as new value and return true. 由于上一步,您无需再次检查它是否为空,只需提取介于1和2之间的数字即可用作新值并返回true。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM