猜數字遊戲-人出題,電腦猜貼)

來源:互聯網
上載者:User

/*
* 檔案名稱: GuessNum.h
* 程式描述:
*    常見的小遊戲【猜數字】的智能解法:
*    猜數字遊戲:    即有四位十進位數字,一般可猜8次
*                每次返回aAbB(A表示數字正確並且位置正確,B表示數字正確但位置不正確)
*                如:假設要猜的數字是1234,如果遊戲者猜0134即返回2A1B(3、4為A,1為B)
*
*    演算法:每次選取熵最大的數字進行猜測,即:貪心演算法
*
*    還有一個程式使用決策樹的方法,參見GuessNumAll.cpp
*    另外還有一個程式GuessNumGame.cpp用來類比猜數字遊戲
*/
#include <vector>
#include <list>
#include <string>
using namespace std;

class           GuessNum
{
/* */
public:
    GuessNum(void);
    void                Guess(void);
    void                PrintStack(void);

/* */
private:
    bool                ConfirmAB(string first, string second, string ab);
    bool                GuessNext(void);
    int                 GetABValue(string first, string second);
    const static int    m_base[5];
    string              m_lastGuess;
    list<string>        m_setAll;
    list<string>        m_setCurr;
    vector<string>      m_stack;
    int                 m_times;
};
/*
[01/19-21:54:50]
猜數字遊戲:
? 即有四位十進位數字,一般可猜8次
? 每次返回aAbB(A表示數字正確並且位置正確,B表示數字正確但位置不正確)
? 如:假設要猜的數字是1234,如果遊戲者猜0134即返回2A1B(3、4為A,1為B)

思路:
? 類比人猜數位過程,先構造一個集合包括所有可能的數字(10*9*8*7=5040種),先亂猜一個,根據返回xAxB來把原來集合裡面的不符合的都刪掉,然後根據選取下一個。選下一個的原則是:選最能區分剩下的集合的那個數,即:被選擇的那個數得到的傳回值為xAxB中任意一種的機率差不多。
? 我使用資訊量的方法,即:
?? 對集合set(size個)中每一個數字n,用n的每一種傳回值(從0a0b到4a0b,共有15種)做刪減,看各剩下多少個,用pi表示第i種傳回值得情況,然後根據資訊量公式:info(n) = ∑(pi/size) * log(pi/size)計算,然後取max(info(i)) i=0..size;最大的那個info(n)對應的數字就是被選擇的數字。

下面是一個由電腦猜數位程式  猜(0-9)中4個全排列中的一個   現在我想修改成(1-9)中選4個全排列中一個. 
-------------------
我修改的思路是:縮小全集範圍 把帶0的4位元字排除 下面紅色為我修改的部分
               修改第一次隨機猜過濾帶0的隨機數
但修改結果:隨機數仍然有0出現.全集也仍然有0  這裡我想慚愧我之前沒有學C++有些看不懂 但對C比較熟悉點.誰能幫小弟弟 指點迷津  或提出你修改的方法  小弟不勝感謝.因為急需這個程式.請幫我修改下
/*
* 檔案名稱: GuessNum.cpp
* 程式描述: 實現GuessNum類
*/
#pragma warning(disable : 4786)
#include <iostream>
#include <algorithm>
#include <ctime>
#include <strstream>
#include <cmath>
#include "GuessNum.h"

const int GuessNum::    m_base[5]={ 0, 5, 9, 12, 14 };

/* */

GuessNum::GuessNum(void)
{
    m_times=0;

    //產生m_setAll
    unsigned int    num=123;
    char            a[10];
    while(num < 10000)
    {
        bool    valid=true;                 //表示數字沒有重複
        sprintf(a, "%04u", num);
        for(int i=0; i < 4; i++)
        {
            for(int j=i + 1; j < 4; j++)
                if(a[i] == a[j]) valid=false;
        }

        for(int q=0; q < 4; q++)
            if(a[q] == '0') valid=false;    //紅色部分為我添加的內容想縮小全集範圍排除帶0的數字
        if(valid) m_setAll.push_back(a);
        num++;
    }   //#while(num)
}       //#GuessNum()

/* */
void GuessNum::Guess(void)
{
    //重設資料集
    m_setCurr.clear();

    list<string>::iterator  itCopy=m_setAll.begin();
    while(itCopy != m_setAll.end()) m_setCurr.push_back(*itCopy++);
    m_stack.clear();
    m_times=0;

    //隨機產生第一次猜測
    srand((unsigned)time(NULL));            //隨機數種子
    bool            valid=false;
    unsigned int    iCode;
    while(!valid)
    {
        iCode=rand();
        while(iCode > 9999) iCode/=10;

        char    a[10];
        sprintf(a, "%04u", iCode);
        valid=true;
        for(int i=0; i < 4; i++)
            for(int j=i + 1; j < 4; j++)
                if(a[i] == a[j]) valid=false;
        for(int q=0; q < 4; q++)
            if(a[q] == '0') valid=false;    //紅色部分為我添加的內容想排除帶0的隨機4位元
        if(valid) m_lastGuess=a;
    }

    while(!GuessNext());
}   //#Guess()

/* */
bool GuessNum::GuessNext(void)
{
    m_times++;

    //進行猜測,擷取猜測結果
    string  result;
    cout << "/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n/n";
    PrintStack();
    cout << "第 " << m_times << " 次猜測: " << m_lastGuess << endl;
    cout << "請輸入結果[?A?B]:";

    bool    valid=false;
    while(!valid)
    {
        cin >> result;

        //判斷輸入是否合法
        if(result.length() == 4 &&
                   result[0] >= '0' &&
                   result[0] <= '4' &&
                   result[2] >= '0' &&
                   result[2] <= '4' &&
                   (result[0] + result[2]) <= ('0' + '4') &&
                   toupper(result[1]) == 'A' &&
                   toupper(result[3]) == 'B')
        {
            valid=true;
        }

        if(!valid) cout << "輸入不合法,請重新輸入:";
    }   //#while

    //將結果入棧
    strstream   strm;
    strm << "第 " << m_times << "次: " << m_lastGuess << " -> " << result << endl;

    string  strTemp;
    getline(strm, strTemp);
    m_stack.push_back(strTemp);
    if(result[0] != '4')
    {
        //尚未猜對, 進行資料集的約簡
        list<string>::iterator  itRemove;
        itRemove=m_setCurr.begin();
        while(itRemove != m_setCurr.end())
        {
            if(!ConfirmAB(m_lastGuess, *itRemove, result))
                itRemove=m_setCurr.erase(itRemove);
            else
                itRemove++;
        }

        //@@
        if(m_setCurr.size() == 0)
        {
            cerr << "你檢查一下,肯定是哪一步輸入錯誤!" << endl;
            cerr << "程式結束" << endl;
            exit(1);
        }
        else if(m_setCurr.size() == 1)
        {
            m_lastGuess=m_setCurr.front();
            return false;
        }

        //@@
        cout << "m_setAll.size() = " << m_setAll.size() << endl;
        cout << "m_setCurr.size() = " << m_setCurr.size() << endl;

        //產生下一個猜測資料
        double                  eMax=0;     //max entropy, 最大資訊量
        string                  strMax;     //提供最大資訊量的那個數串
        list<string>::iterator  itEn=m_setCurr.begin();

        //計算用每一個數來做區分時的資訊量,取提供最大資訊量的那個
        double                  eCurr=0;
        int                     abList[15]; //從0a0b到4a0b共15種情況
        memset(abList, 0, 15 * sizeof(int) / sizeof(char));
        while(itEn != m_setCurr.end())
        {
            list<string>::iterator  itTemp=m_setCurr.begin();
            while(itTemp != m_setCurr.end())
            {
                abList[GetABValue(*itEn, *itTemp)]++;
                itTemp++;
            }

            //統計熵

            //@@

            //            cout << "sigh.." << *itEn << endl;
            double  eTemp=0;
            double  eDiv=0;
            for(int i=0; i < 15; i++)
            {
                if(abList[i] != 0)          //避免0*log0
                {
                    eDiv=double(abList[i]) / double(m_setCurr.size());
                    eTemp+= -eDiv * log(eDiv);
                }
            }

            if(eTemp > eMax)
            {
                cout << "here eMax = " << eMax << endl;
                eMax=eTemp;
                strMax=*itEn;
            }

            itEn++;
        }   //#while(itEn)
        m_lastGuess=strMax;
        return false;
    }       //#if(result[0] != 4)
    else    // result[0] == 4
    {
        cout << "/n答案是: " << m_lastGuess << endl;
        cout << "一共用了 " << m_times << "次" << endl;
        PrintStack();
        return true;
    }
}           //#GuessNext()

/* */
void GuessNum::PrintStack(void)
{
    for(int i=0; i < m_stack.size(); i++) cout << m_stack[i] << endl;
}   //#PrintStack()

/* */
inline bool GuessNum::ConfirmAB(string first, string second, string ab)
{
    int a=0, b=0;
    for(int i=0; i < 4; i++)
    {
        for(int j=0; j < 4; j++)
            if(first[i] == second[j])
                if(i == j)
                    a++;
                else
                    b++;
    }

    if(ab[0] == char(a + '0') && ab[2] == char(b + '0'))
        return true;
    else
        return false;
}   //#ConfirmAB()

/* */
inline int GuessNum::GetABValue(string first, string second)
{
    int a=0;
    int b=0;
    for(int i=0; i < 4; i++)
    {
        for(int j=0; j < 4; j++)
            if(first[i] == second[j])
                if(i == j)
                    a++;
                else
                    b++;
    }

    return m_base[a] + b;
}   //#GetABValue()
//測試程式
#include <iostream>
#include "GuessNum.h"
using namespace std;

int main()
{
    GuessNum gn;
    cout << "GuessNum object created..." << endl;
    gn.Guess();
    return 0;
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.