C++ AI解珠玑妙算(mastermind)算法

Posted 传说C罗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ AI解珠玑妙算(mastermind)算法相关的知识,希望对你有一定的参考价值。

珠玑妙算这个游戏大家都不陌生,规则就不多说了,直接进主题:

需要破译的密码由四位组成,每位可以是0~9中的任意数字。eg. (1544,4301,0918,...)

此算法可在20步内猜测出结果。

算法大致步骤分为两步:

第一步:求出这串密码是由哪四个数字组成。从0000迭代到9999就行,第一步最多需要十次猜测。

第二步:将由第一步得出的四个数字全排列,把全排列结果存在一个集合里。然后依次返回集合里的猜测并通过猜测结果做简单的划分。对集合进行进一步的消除从而减少猜测次数。

划分规则如下:

当结果猜中数为0时:因为0位猜中,所以四个位的数字都是错的。从而我们可以直接消除集合里所有与此猜测有相同位的元素。举例:假设猜测为“1234”并且猜中数为0,我们就可以把集合里所有第一位为1,第二位为2,第三位为3,第四位为4 的元素全部消除掉。

当结果猜中数为2时:这种情况稍微复杂点,具体操作如下:把该猜测和之前猜中数为2的猜测做比对,若二者中有且仅有一位数字同位,那么该数字在密码中就属于该位。举例:假设“1234”的猜中数为2,“4132”猜中数也为2,通过比对这两串数字得知它们的第三位是相同的,都为3,所以可以得知真正密码的第三位就是3。然后回到我们的集合把第三位不为3的元素全部消除。

当结果猜中数为1,3,4时,不予任何操作。

整体算法如上所述。我的算法是以一个函数的形式运行的:string mastermindAI(int rr, int rw)

这个函数每次被呼叫都会返回一个猜测(string),然后主程序将会以参数形式将猜测结果传给函数(rr为真猜中数量,rw为伪猜中数量)。第一次被呼叫时rr和rw为0。

珠玑妙算的主程序会在下一篇博客中。

学习编程一年一来的第一篇博客,不足之处请赐教。

程序:

string mastermindAI(int rr,int rw){
    static const int SIZE=10000;//How many guesses to save
    static string gHistory[SIZE];//guess history
    static int rHistory[SIZE];//result history
    static int hisCount=0;// history counter
    static string sGuess="0000";       //Size the guest string
    static int guessNum=0;
    static char bit[4];
    static int bitSize=4;
    static int bitNum=0;
    static vector<string> guessBase;
    static bool once=true;
    static bool beforeSecondStep=false;   
 //第一步:迭代返回0-9,求出四位数字
    if(bitNum<4)
    {
        if(rr>0)
        {
            for(int i=0;i<rr;i++)
            {        
                bit[bitNum]=sGuess[1];
                bitNum++;
            }
        }
        if(bitNum<4)
        {
            for(int i=0;i<4;i++)
            {
                sGuess[i]=guessNum+'0';
            }
        }    
    }
    //当四位数字都找到时,进入第二步:
    if(bitNum>=4)
    {
        vector<string>::iterator it;
        if(once)    //进入第二步后,首先把四位数字全排列,所有排列组合将被存入名为guessbase的容器中
        {   //由此到156行为全排列算法
            for(int i=0;i<4;i++)
            {
                for(int j=i+1;j<4;j++)
                {
                    if(bit[i]==bit[j])
                    {
                        bitSize--;
                    }
                }
            }
            for(int i=0;i<4;i++)
            {
                for(int j=0;j<3;j++)
                {
                    if(bit[j]>bit[j+1])
                    {
                        char temp;
                        temp=bit[j];
                        bit[j]=bit[j+1];
                        bit[j+1]=temp;
                    }
                }
            }
            string stemp=bit;
            guessBase.push_back(stemp);
            for(int i=3;i>0;i--)    //permutation the bit[]
            {
                if(bit[i-1]<bit[i])
                {
                    char minIdx=i;
                    for(int j=i;j<4;j++)
                    {
                        if(bit[j]>bit[i-1])
                        {
                            if(bit[j]<=bit[minIdx])
                            {
                                minIdx=j;
                            }
                        }
                    }
                    char temp;
                    temp=bit[minIdx];
                    bit[minIdx]=bit[i-1];
                    bit[i-1]=temp;
                    for(int j=i,k=3;j<k;j++,k--)
                    {
                        temp=bit[j];
                        bit[j]=bit[k];
                        bit[k]=temp;
                    }
                    stemp=bit;
                    guessBase.push_back(stemp);
                    i=4;
                }
            }
            once=false;
        }
        //全排列结束,返回guessbase容器里的第一个元素,然后擦除
        if(beforeSecondStep==false)
        {
            sGuess=guessBase[0];
            it=guessBase.begin();
            it=guessBase.erase(it);
            beforeSecondStep=true;
        }
        else    //下面进入到划分环节
        {
            gHistory[hisCount]=sGuess;
            rHistory[hisCount]=rr;
            hisCount++;
            switch(rr)  //当真猜中数为0和2时进行划分,其他猜中数不划分
            {
                case 0:
                    for(it=guessBase.begin();it!=guessBase.end();)
                    {
                        string temp=*it;
                        if(temp[0]==sGuess[0]||temp[1]==sGuess[1]||temp[2]==sGuess[2]||temp[3]==sGuess[3])
                        {
                            it=guessBase.erase(it);
                        }
                        else
                        {
                            it++;
                        }
                    }
                    break;
                case 2:
                    if(bitSize==4||bitSize==3)
                    {                       
                        for(int i=0;i<hisCount;i++)
                        {
                            int rNum=0;
                            int idx=0;
                            if(rHistory[i]==2)
                            {
                                for(int j=0;j<4;j++)
                                {
                                    if(gHistory[i][j]==sGuess[j])
                                    {
                                        rNum++;
                                        idx=j;
                                    }
                                }
                                if(rNum==1)
                                {
                                    for(it=guessBase.begin();it!=guessBase.end();)
                                    {
                                        string temp=*it;
                                        if(temp[idx]!=sGuess[idx])
                                        {
                                            it=guessBase.erase(it);
                                        }
                                        else
                                        {
                                            it++;
                                        }
                                    }
                                }
                            }
                        }
                    
                    }
                    break;    
                default:
                    break;                  
            }
            sGuess=guessBase[0];
            it=guessBase.begin();
            it=guessBase.erase(it);
        }
        
    }
    guessNum++;
    //Return the result
    return sGuess;
}

 

以上是关于C++ AI解珠玑妙算(mastermind)算法的主要内容,如果未能解决你的问题,请参考以下文章

C++ AI解珠玑妙算(mastermind)算法

C++ AI解珠玑妙算(mastermind)算法

c++ 珠玑妙算(mastermind) 自动版

c++ 珠玑妙算(mastermind) 自动版

c++ 珠玑妙算(mastermind) 自动版

c++ 珠玑妙算(mastermind) 自动版