Search code examples
c++mathmathematical-expressions

I'm trying to find out six values based on 4 equations


This code currently outputs 0 1 0 1 1 2 F0 0 1 0 1 1 2 F1 0 1 0 1 1 3 F0 0 1 0 1 1 3 F1 0 1 0 1 1 4 F0 etc. I'm trying to find out the correct values of green, yellow, purple, orange, red and blue using brute force These values can't repeat (i.e. if red = 0 then blue != 0), but I figured this code would give me multiple solutions, from which I could choose the correct one. My question is: what is wrong with this?

#include <iostream>
using namespace std;

int main()
{
int green, yellow, purple, orange, red, blue, finalresult;
int result1, result2, result3, result4, result5, result6, fresult1, fresult2;

for (green = 0; green < 10; green++)
{

    for (yellow = 0; yellow < 10; yellow++)
    {
        for (yellow = yellow; yellow == green; yellow++)
        {
            yellow = yellow;
        }
        for (purple = 0; purple < 10; purple++)
        {
            for (purple = purple; purple == yellow; purple++)
            {
                purple = purple;
            }
             for (orange = 0; orange < 10; orange++)
             {
                for (orange = orange; orange == purple; orange++)
                {
                    orange = orange;
                }
                  for (red = 1; red < 10; red++)
                  {
                        for (red = red; red == purple; red++)
                        {
                            red = red;
                        }
                        for (blue = 1; blue < 10; blue++)
                        {
                            for (blue = blue; blue == red; blue++)
                            {
                                blue = blue;
                            }
                            finalresult = 0;
                            if(green * yellow == purple * 10 + green)
                            {
                                cout << green << endl << yellow << endl << purple << endl << orange << endl << red << endl << blue << endl;
                                cout << "F" << finalresult << endl;
                                finalresult++;
                            }
                            if (purple * 10 + orange / red == red)
                            {
                                cout << green << endl << yellow << endl << purple << endl << orange << endl << red << endl << blue << endl;
                                cout << "F" << finalresult << endl;
                                finalresult++;
                            }
                            if (yellow * 10 + orange == red * blue)
                            {
                                cout << green << endl << yellow << endl << purple << endl << orange << endl << red << endl << blue << endl;
                                cout << "F" << finalresult << endl;
                                finalresult++;
                            }
                            if (green == red * 10 + green / blue)
                            {
                                cout << green << endl << yellow << endl << purple << endl << orange << endl << red << endl << blue << endl;
                                cout << "F" << finalresult << endl;
                                finalresult++;
                            }
                            if (finalresult == 4)
                            {
                                cout << "V" << endl <<"V" << endl << "V" << endl << "V" << endl << "V" << endl << "V" << endl << "V" << endl << "V" << endl << "V" << endl << "V" << endl << "V" << endl << "V" << endl << "V" << endl;
                                cout << green << endl << yellow << endl << purple << endl << orange << endl << red << endl << blue << endl;

                            }
                        }

                  }

             }

        }

    }

}

}


Solution

  • If I understood the problem, you have to choose between all the possible combinations of distinct color values the ones that solve your four equations.

    The nested loops in OP's code will provide (almost, some loops start at 1) all the possible combinations, but the way choosen to exclude the duplicate values is completely wrong.

    The equations also, could be checked in one single condition.

    The following code should give the expected result:

    #include <iostream>
    
    int main(void)
    {
        long int n = 0, solutions = 0;
    
        for (int green = 0; green < 10; ++green)
        {
            for (int yellow = 0; yellow < 10; ++yellow)
            {
                if ( yellow == green )    // skip the duplicate values
                    continue;
    
                for (int purple = 0; purple < 10; ++purple)
                {
                    if ( purple == green  ||  purple == yellow )
                        continue;
    
                    for (int orange = 0; orange < 10; ++orange)
                    {
                        if ( orange == green  ||  orange == yellow  ||  orange == purple )
                            continue;
    
                        for (int red = 0; red < 10; ++red)
                        {
                            if ( red == green   ||  red == yellow  ||
                                 red == purple  ||  red == orange)
                                continue;
    
                            for (int blue = 0; blue < 10; ++blue)
                            {
                                if ( blue == green   ||  blue == yellow  ||
                                     blue == purple  ||  blue == orange  ||  blue == red )
                                    continue;
    
                                // Now check if the values solve all the equations
                                // Assuming that you don't want integer divisions 
                                if (   purple * 10 + green  == green * yellow
                                    && purple * 10 + orange == red * red
                                    && yellow * 10 + orange == red * blue
                                    &&    red * 10 + green  == green * blue)
                                {
                                    std::cout << "Green:  " << green
                                        << "\nYellow: " << yellow
                                        << "\nPurple: " << purple
                                        << "\nOrange: " << orange
                                        << "\nRed:    " << red
                                        << "\nBlue:   " << blue << '\n';
                                    ++solutions;
                                }
                                ++n;
                            }
                        }
                    }
                }
            }
        }
        // The number of different combinations should be 10 * 9 * 8 * 7 * 6 * 5 = 151200 
        std::cout << "\nCombinations tested: " << n
            << " (out of " << 10*10*10*10*10*10 << ")\n"
            << "Solutions: " << solutions << '\n';
    }
    

    Once executed, it outputs:

    Green:  5
    Yellow: 3
    Purple: 1
    Orange: 6
    Red:    4
    Blue:   9
    
    Combinations tested: 151200 (out of 1000000)
    Solutions: 1
    

    EDIT

    Spurred by Jarod42's answer, I'd like to show a more efficient solution, which takes advantages of the standard library function std::next_permutation (and std::prev_permutation too) and instead of skipping the unwanted permutations, directly generates only the needed ones.

    #include <iostream>
    #include <vector>
    #include <array>
    #include <algorithm>
    #include <numeric>
    
    // Applies f() to all the permutations of n values taken k at a time
    // where k is the size of the range [first, last)
    // n!/(n − k)! iterations are performed
    template<class Iterator, class Func>
    void for_each_n_permute_k(int n, Iterator first, Iterator last, Func f);
    
    int main()
    {
        std::array<int, 6> chosen;
        int solutions = 0;
    
        for_each_n_permute_k(10, chosen.begin(), chosen.end(), [&chosen, &solutions] () {
            auto & [green, yellow, purple, orange, red, blue] = chosen;
    
            if (   purple * 10 + green  == green * yellow
                && purple * 10 + orange == red * red
                && yellow * 10 + orange == red * blue
                &&    red * 10 + green  == green * blue)
            {
                std::cout << "Solution found (" << ++solutions << ")\n"
                    << "Green:  " << green
                    << "\nYellow: " << yellow
                    << "\nPurple: " << purple
                    << "\nOrange: " << orange
                    << "\nRed:    " << red
                    << "\nBlue:   " << blue << '\n';
            }
        });
    }
    
    // copy the elements from [it1, last) to dest if the predicate applied to
    // the corresponding element of [it2, it2 + distance(it1, last)) returns true
    template<class Input1It, class Input2It, class OutputIt, class Predicate>
    constexpr OutputIt select_if(Input1It it1, Input1It last,
                                 Input2It it2, OutputIt dest, Predicate pred)
    {
        for( ; it1 != last; ++it1, ++it2)
        {
            if (pred(*it2))
            {
                *dest++ = *it1;
            } 
        }
        return dest;
    }
    
    template<class Iterator, class Func>
    void for_each_n_permute_k(int n, Iterator first, Iterator last, Func f)
    {
        // e.g. for n == 10 -> {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        std::vector<int> numbers(n);
        std::iota(numbers.begin(), numbers.end(), 0);
    
        // e.g. for n == 10 and k == 6 -> {1, 1, 1, 1, 1, 1, 0, 0, 0, 0};
        std::vector<int> flags(n);
        std::fill(flags.begin(), flags.begin() + std::distance(first, last), 1);
    
        long long int tested = 0;
    
        do
        {
            // choose the k elements, e.g. for n == 10 and k == 6 -> {0, 1, 2, 3, 4, 5};
            select_if(numbers.begin(), numbers.end(), flags.begin(), first,
                      [] (int x) { return x == 1; });
            do
            {
                ++tested;
                f();
            } while (std::next_permutation(first, last));
    
        // 'flags' starts sorted in descending order, so I need the previous permutation
        } while (std::prev_permutation(flags.begin(), flags.end())); 
    
        std::cout << "\nPermutations tested: " << tested << '\n';
    }
    

    It finds the same solution traversing all and only the distinct (10! / (10 - 6)!) = 151 200 permutations.