有比许多嵌套“for”循环更好的东西吗?

Tim*_*all 3 c++

我希望评估游戏的几种不同的潜在规则/评分系统。该游戏涉及掷三个骰子,最多掷三次。为了考虑每种可能性的结果,我迭代了九次可能的骰子掷中每一次的所有可能值。

\n

我的问题是以下强力风格编码是否是最好的方法。

\n
// get the result for each possible game\nvoid Evaluate( const ScoringSystem& sys )\n{\n    for( int d1=0; d1<6; ++d1 )\n    {\n        for( int d2=0; d2<6; ++d2 )\n        {\n            for( int d3=0; d3<6; ++d3 )\n            {\n                for( int d4=0; d4<6; ++d4 )\n                {\n                    for( int d5=0; d5<6; ++d5 )\n                    {\n                        for( int d6=0; d6<6; ++d6 )\n                        {\n                            for( int d7=0; d7<6; ++d7 )\n                            {\n                                for( int d8=0; d8<6; ++d8 )\n                                {\n                                    for( int d9=0; d9<6; ++d9 )\n                                    {\n                                        int rolls[] = { d1, d2, d3, d4, d5, d6, d7, d8, d9 };\n\n                                        // get the result for this particular game\n                                        sys.GetGameResult( rolls );\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

该代码可以运行,但很丑陋,并且无法扩展到具有更多骰子的游戏。我有一个支持 C++17 的环境,因此我愿意接受更新的想法 \xe2\x80\x94,只要它们不会使代码看起来太糟糕。

\n

(正切:6^9 超过 1000 万。我可能最好使用伪随机数,并且只是“掷”九个骰子一百万次。但我仍然想知道是否有一种聪明的方法来完成排列。)

\n

Kev*_*vin 11

如果您发现嵌套的循环看起来几乎相同,您应该考虑使用递归。

void generateDiceRolls(const ScoringSystem& sys, std::vector<int>& rolls, size_t index)
{
    if (index == rolls.size())
    {
        // Reached the end - all the dice have been rolled
        sys.GetGameResult(rolls);
    }
    else
    {
        // For each value of a die at this index, generate dice rolls for the rest of them
        for (int i = 0; i < 6; i++)
        {
            rolls[index] = i;
            generateDiceRolls(sys, rolls, index + 1);
        }
    }
}
void Evaluate(const ScoringSystem& sys)
{
    std::vector<int> rolls(9);  // Change 9 to however many dice you want to use
    generateDiceRolls(sys, rolls, 0);
}
Run Code Online (Sandbox Code Playgroud)


Jar*_*d42 5

一些库如range-v3建议cartesian_product允许更简单:

std::array<int, 6> dice_range{1, 2, 3, 4, 5, 6};
for (auto t : ranges::view::cartesian_product(dice_range, dice_range, dice_range,
                                              dice_range, dice_range, dice_range,
                                              dice_range, dice_range, dice_range))
{
    std::cout << std::get<0>(t)
              << std::get<1>(t)
              << std::get<2>(t)
              /* << .. */
              << std::endl;
    std::apply([](auto... args){ (std::cout << ... << args) << std::endl; }, t); // C++17
}
Run Code Online (Sandbox Code Playgroud)

如果没有外部库,您可以使用“增加”的向量:

bool increase(std::vector<std::size_t>& it, std::size_t max)
{
    for (std::size_t i = 0, size = it.size(); i != size; ++i) {
        const std::size_t index = size - 1 - i;
        ++it[index];
        if (it[index] >= max) {
            it[index] = 0;
        } else {
            return true;
        }
    }
    return false;
}

template <typename F>
void iterate(F f, std::size_t size, std::size_t max = 6)
{
    std::vector<std::size_t> it(size, 0);

    do {
        f(it);
    } while (increase(it, max));
}

int main()
{
    iterate([](const auto& v){ for (auto e : v) std::cout << 1 + e; std::cout << std::endl; }, 4);
}
Run Code Online (Sandbox Code Playgroud)

演示