শব্দটি অনুমান করুন (ওরফে লিঙ্গো)


13

এই চ্যালেঞ্জের লক্ষ্যটি হ'ল চেষ্টা করা সম্ভবতম সংখ্যায় একটি শব্দ অনুমান করতে সক্ষম একটি প্রোগ্রাম লিখতে। এটি লিঙ্গো টিভি শো ( http://en.wikedia.org/wiki/Lingo_(US_game_show) এর ধারণার উপর ভিত্তি করে ।

বিধি

কমান্ড লাইনে প্রথম যুক্তি হিসাবে একটি শব্দের দৈর্ঘ্য দেওয়া হয়েছে, প্লেয়ার প্রোগ্রামটি তার একক চরিত্রের পরে তার স্ট্যান্ডার্ড আউটপুটটিতে অনুমান লিখে শব্দটি অনুমান করার জন্য পাঁচটি প্রচেষ্টা নিষ্পত্তি করে \n

অনুমান করার পরে, প্রোগ্রামটি তার স্ট্যান্ডার্ড ইনপুটটিতে একটি স্ট্রিং দেয়, তার পরে একটি একক \nঅক্ষরও থাকে।

স্ট্রিংটির অনুমানের শব্দের সমান দৈর্ঘ্য রয়েছে এবং নিম্নলিখিত অক্ষরের ক্রমটি সমন্বিত:

  • X: যার অর্থ যে প্রদত্ত চিঠিটি অনুমান করার জন্য শব্দটিতে উপস্থিত নেই
  • ?: যার অর্থ যে প্রদত্ত চিঠিটি অনুমান করার জন্য শব্দটিতে উপস্থিত রয়েছে তবে অন্য কোনও স্থানে রয়েছে
  • O: যার অর্থ এই অবস্থানের চিঠিটি সঠিকভাবে অনুমান করা হয়েছে

উদাহরণস্বরূপ, যদি অনুমান করতে শব্দ dents, এবং প্রোগ্রাম শব্দ পাঠায় dozes, এটা পাবেন OXX?Oকারণ dএবং sসঠিক হয়, eভুল হয়, এবং oএবং zউপস্থিত না।

সাবধান যে যদি একটি চিঠি অনুমান করার শব্দ তুলনায় মনন প্রয়াস আরও উপস্থিত বার, এটা হবে না হিসেবে চিহ্নিত করা ?এবং Oশব্দ অনুমান করার জন্য চিঠির occurences সংখ্যা বেশি বার। উদাহরণস্বরূপ, যদি অনুমানের শব্দটি হয় coziesএবং প্রোগ্রামটি প্রেরণ করে তবে tossesএটি প্রাপ্ত হবে XOXXOOকারণ এটির সন্ধানের জন্য কেবল একটিই রয়েছে s

শব্দ একটি ইংরেজি শব্দ তালিকা থেকে চয়ন করা হয়। প্রোগ্রাম দ্বারা প্রেরিত শব্দটি যদি সঠিক দৈর্ঘ্যের একটি বৈধ শব্দ না হয় তবে প্রচেষ্টাটিকে একটি স্বয়ংক্রিয় ব্যর্থতা হিসাবে বিবেচনা করা হয় এবং কেবলমাত্র Xফিরে আসে।
প্লেয়ার প্রোগ্রামটি ধরে নেওয়া উচিত যে নামক wordlist.txtএবং প্রতি লাইনে একটি শব্দ যুক্ত একটি ফাইল বর্তমান কার্যনির্বাহী ডিরেক্টরিতে উপস্থিত রয়েছে এবং প্রয়োজনীয় হিসাবে পড়া যেতে পারে।
অনুমানগুলি কেবল বর্ণানুক্রমিক লো-কেস অক্ষর ( [a-z]) দ্বারা গঠিত হওয়া উচিত ।
প্রোগ্রামের জন্য অন্য কোনও নেটওয়ার্ক বা ফাইল অপারেশন অনুমোদিত নয়।

গেমটি তখন শেষ হয় যখন কেবল একটি স্ট্রিং নিয়ে Oআসে বা প্রোগ্রামটি 5 টি প্রচেষ্টা করার পরেও শব্দটি অনুমান করতে সক্ষম হয় না।

স্কোরিং

একটি গেমের স্কোর প্রদত্ত সূত্র দ্বারা দেওয়া হয়:

score = 100 * (6 - number_of_attempts)

সুতরাং প্রথম চেষ্টাটিতে যদি শব্দটি সঠিকভাবে অনুমান করা হয় তবে 500 পয়েন্ট দেওয়া হবে। শেষ চেষ্টাটি 100 পয়েন্টের মূল্যবান।

শব্দটি অনুমান করতে ব্যর্থতা শূন্য পয়েন্ট দেয়।

খাঁদ

প্লেয়ার প্রোগ্রামগুলি প্রতিটি শব্দের দৈর্ঘ্যের জন্য 4 থেকে 13 বর্ণের মধ্যে 100 টির মতো এলোমেলো শব্দ অনুমান করার চেষ্টা করে তাদের মূল্যায়ন করা হবে।
র্যান্ডম শব্দের নির্বাচন অগ্রিম দ্বারা সম্পন্ন হবে সুতরাং সমস্ত এন্ট্রি একই শব্দ অনুমান করতে হবে।

বিজয়ী প্রোগ্রাম, এবং গৃহীত উত্তর, সর্বোচ্চ স্কোর পৌঁছানোর এক হবে।

Https://github.com/noirotm/lingo কোডটি ব্যবহার করে একটি উবুন্টু ভার্চুয়াল মেশিনে প্রোগ্রামগুলি পরিচালনা করা হবে । যেকোন ভাষায় প্রয়োগগুলি যতক্ষণ না তাদের সংকলন এবং / অথবা চালানোর জন্য যুক্তিসঙ্গত নির্দেশাবলী দেওয়া হয় ততক্ষণ তা গৃহীত হয়।

আমি গিট সংগ্রহস্থলে রুবিতে কয়েকটি পরীক্ষার বাস্তবায়ন সরবরাহ করছি, তাদের কাছ থেকে অনুপ্রেরণা নিতে নির্দ্বিধায়।

এই প্রশ্নটি পর্যায়ক্রমে প্রকাশিত উত্তরের জন্য র‌্যাঙ্কিংয়ের সাথে আপডেট করা হবে যাতে চ্যালেঞ্জাররা তাদের এন্ট্রিগুলি উন্নত করতে পারে।

সরকারী চূড়ান্ত মূল্যায়নটি 1 জুলাই অনুষ্ঠিত হবে

হালনাগাদ

wordlistN.txt4 এবং 13 এর মধ্যে এন এর বর্তমান শব্দ দৈর্ঘ্যের জন্য শব্দ তালিকার গতি বাড়ানোর জন্য এন্ট্রিগুলি এখন ফাইলগুলির উপস্থিতি ধরে নিতে পারে ।

উদাহরণস্বরূপ, এখানে wordlist4.txtচারটি অক্ষরের শব্দের সমন্বয়যুক্ত একটি ফাইল রয়েছে এবং wordlist10.txtদশটি অক্ষরের শব্দ রয়েছে containing

প্রথম রাউন্ডের ফলাফল

2014-07-01 তারিখে, নিম্নলিখিত ফলাফল সহ তিনটি এন্ট্রি জমা দেওয়া হয়েছে:

                        4       5       6       7       8       9       10      11      12      13      Total
./chinese-perl-goth.pl  8100    12400   15700   19100   22100   25800   27900   30600   31300   33600   226600
java Lingo              10600   14600   19500   22200   25500   28100   29000   31600   32700   33500   247300
./edc65                 10900   15800   22300   24300   27200   29600   31300   33900   33400   33900   262600

** Rankings **
1: ./edc65 (262600)
2: java Lingo (247300)
3: ./chinese-perl-goth.pl (226600)

সমস্ত এন্ট্রি অবিচ্ছিন্নভাবে সম্পাদন করেছে, একটি স্পষ্ট বিজয়ীর সাথে, @ এডসি 65 এর সি ++ এর এন্ট্রি।

সমস্ত প্রতিযোগী বেশ দুর্দান্ত। আমি @ চীনা-পার্ল-গোথকে মারতে এমনকি এখনও সক্ষম হয়েছি।
যদি আরও এন্ট্রি জমা দেওয়া হয় তবে আরেকটি মূল্যায়ন হবে। আপনি যদি আরও ভাল করতে পারেন বলে মনে করেন বর্তমান এন্ট্রিগুলিও উন্নত করা যায়।


1
কেবল স্পষ্ট করে বলার জন্য: প্রোগ্রামটি যদি 6 টিরও বেশি শব্দটি অনুমান করার চেষ্টা করে তবে এটি কি নেতিবাচক পয়েন্ট পায় বা কেবল শূন্য? অন্য কথায়, negativeণাত্মক পয়েন্টগুলি এড়ানোর চেষ্টা করার পরে আমাদের প্রোগ্রামটি বন্ধ করার জন্য কি যুক্তি প্রয়োজন? (প্রোগ্রামটি শব্দটি অনুমান করতে ব্যর্থ হলে বিধিগুলি শূন্য পয়েন্ট বলে)
ড্যাঙ্কমেস

1
@ জোভ গেমস পাঁচটি চেষ্টা করার পরে, আপনার প্রোগ্রামটি প্রস্থান করা উচিত, তবে গেম ইঞ্জিন যদি এটি করতে অস্বীকার করে তবে জোর করেই এটি বন্ধ করে দেবে :)
স্যারডিয়ারিয়াস 9'14

1
@ রিচার্ড হ্যাঁ ঠিক, পাইথনের বিষয়ে চিন্তা করবেন না, এটি প্রথম শ্রেণির নাগরিক, সুতরাং পাইথন কোড চালাতে আমার কোনও সমস্যা হবে না :)
স্যারডিয়ারিয়াস

1
@ ظلمহালফ তার জন্য অনেক ধন্যবাদ! অবশেষে আমি চালিয়ে যেতে পারি!
মিস্টারব্লায় 20'14

1
@ ঠিকঠাক ভাল ধারণা আসলেই, আমি এটি বাস্তবায়নের চেষ্টা করব
স্যারডিয়ারিয়াস

উত্তর:


5

সি ++ 267700 পয়েন্ট

পুরানো মাস্টারমাইন্ড ইঞ্জিনের একটি পোর্টিং।
মাস্টারমাইন্ড থেকে পার্থক্য:

  • আরও স্লট
  • আরও প্রতীক
  • বড় সমাধানের স্থান (তবে এত বেশি নয়, কারণ সমস্ত প্রতীক সংমিশ্রণ অনুমোদিত নয়)
  • প্রতিক্রিয়াটি অনেক তথ্যবহুল, সুতরাং প্রতিটি অনুমানের পরে আমাদের কাছে আরও তথ্য রয়েছে
  • প্রতিক্রিয়া উত্পন্ন করতে ধীর এবং এটি একটি করুণ কারণ আমার অ্যালগরিদম এটিকে অনেক কিছু করতে হবে।

মূল ধারণাটি এমন শব্দটি বেছে নিচ্ছে যা সমাধানের স্থানটি হ্রাস করে। প্রথম অনুমানের জন্য অ্যালগরিদমটি সত্যিই ধীর (যার অর্থ 'দিনগুলি') তবে সেরা প্রথম অনুমানটি কেবল লেন শব্দের উপর নির্ভর করে, সুতরাং এটি উত্সটিতে হার্ডকোডযুক্ত। অন্যান্য অনুমানগুলি সেকেন্ডের ক্ষেত্রে করা হয়।

কোড

(G ++ -O3 দিয়ে সংকলন করুন)

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <ctime>
#include <cstdlib>

using namespace std;

class LRTimer
{
private:
    time_t start;
public:
    void startTimer(void)
    {
        time(&start);
    }

    double stopTimer(void)
    {
        return difftime(time(NULL),start);
    } 

};

#define MAX_WORD_LEN 15
#define BIT_QM 0x8000

LRTimer timer;
int size, valid, wordLen;

string firstGuess[] = { "", "a", "as", "iao", "ares", 
    "raise", "sailer", "saltier", "costlier", "clarities", 
    "anthelices", "petulancies", "incarcerates", "allergenicity" };

class Pattern
{
public:
    char letters[MAX_WORD_LEN];
    char flag;
    int mask;

    Pattern() 
        : letters(), mask(), flag()
    {
    }

    Pattern(string word) 
        : letters(), mask(), flag()
    {
        init(word);
    }

    void init(string word)
    {
        const char *wdata = word.data();
        for(int i = 0; i < wordLen; i++) {
            letters[i] = wdata[i];
            mask |= 1 << (wdata[i]-'a');
        }
    }

    string dump()
    {
        return string(letters);
    }

    int check(Pattern &secret)
    {
        if ((mask & secret.mask) == 0)
            return 0;

        char g[MAX_WORD_LEN], s[MAX_WORD_LEN];
        int r = 0, q = 0, i, j, k=99;
        for (i = 0; i < wordLen; i++)
        {
            g[i] = (letters[i] ^ secret.letters[i]);
            if (g[i])
            {
                r += r;
                k = 0;
                g[i] ^= s[i] = secret.letters[i];
            }
            else
            {
                r += r + 1;
                s[i] = 0;
            }
        }
        for (; k < wordLen; k++)
        {
            q += q;
            if (g[k]) 
            {
                for (j = 0; j < wordLen; j++)
                    if (g[k] == s[j])
                    {
                        q |= BIT_QM;
                        s[j] = 0;
                        break;
                    }
            }
        }
        return r|q;
    }

    int count(int ck, int limit);

    int propcheck(int limit);

    void filter(int ck);
};

string dumpScore(int ck)
{
    string result(wordLen, 'X');
    for (int i = wordLen; i--;)
    {
        result[i] = ck & 1 ? 'O' : ck & BIT_QM ? '?' : 'X';
        ck >>= 1;
    }
    return result;
}

int parseScore(string ck)
{
    int result = 0;
    for (int i = 0; i < wordLen; i++)
    {
        result += result + (
            ck[i] == 'O' ? 1 : ck[i] == '?' ? BIT_QM: 0
        );
    }
    return result;
}

Pattern space[100000];

void Pattern::filter(int ck)
{
    int limit = valid, i = limit;
//  cerr << "Filter IN Valid " << setbase(10) << valid << " This " << dump() << "\n"; 

    while (i--)
    {
        int cck = check(space[i]);
//      cerr << setbase(10) << setw(8) << i << ' ' << space[i].dump() 
//          << setbase(16) << setw(8) << cck << " (" << Pattern::dumpScore(cck) << ") ";

        if ( ck != cck )
        {
//          cerr << " FAIL\r" ;
            --limit;
            if (i != limit) 
            {
                Pattern t = space[i];
                space[i] = space[limit];
                space[limit] = t;
            }
        }
        else
        {
//          cerr << " PASS\n" ;
        }
    }
    valid = limit;
//  cerr << "\nFilter EX Valid " << setbase(10) << valid << "\n"; 
};

int Pattern::count(int ck, int limit)
{
    int i, num=0;
    for (i = 0; i < valid; ++i)
    {
        if (ck == check(space[i]))
            if (++num >= limit) return num;
    }
    return num;
}

int Pattern::propcheck(int limit)
{
    int k, mv, nv;

    for (k = mv = 0; k < valid; ++k)
    {
        int ck = check(space[k]);
        nv = count(ck, limit);
        if (nv >= limit)
        {
            return 99999;
        }
        if (nv > mv) mv = nv;
    }
    return mv;
}

int proposal(bool last)
{
    int i, minnv = 999999, mv, result;

    for (i = 0; i < valid; i++) 
    {
        Pattern& guess = space[i];
//      cerr << '\r' << setw(6) << i << ' ' << guess.dump();
        if ((mv = guess.propcheck(minnv)) < minnv)
        {
//          cerr << setw(6) << mv << ' ' << setw(7) << setiosflags(ios::fixed) << setprecision(0) << timer.stopTimer() << " s\n";
            minnv = mv;
            result = i;
        }
    }   
    if (last) 
        return result;
    minnv *= 0.75;
    for (; i<size; i++) 
    {
        Pattern& guess = space[i];
//      cerr << '\r' << setw(6) << i << ' ' << guess.dump();
        if ((mv = guess.propcheck(minnv)) < minnv)
        {
//          cerr << setw(6) << mv << ' ' << setw(7) << setiosflags(ios::fixed) << setprecision(0) << timer.stopTimer() << " s\n";
            minnv = mv;
            result = i;
        }
    }   
    return result;
}

void setup(string wordfile)
{
    int i = 0; 
    string word;
    ifstream infile(wordfile.data());
    while(infile >> word)
    {
        if (word.length() == wordLen) {
            space[i++].init(word);
        }
    }
    infile.close(); 
    size = valid = i;
}

int main(int argc, char* argv[])
{
    if (argc < 2) 
    {
        cerr << "Specify word length";
        return 1;
    }

    wordLen = atoi(argv[1]);

    timer.startTimer();
    setup("wordlist.txt");
    //cerr << "Words " << size 
    //  << setiosflags(ios::fixed) << setprecision(2)
    //  << " " << timer.stopTimer() << " s\n";

    valid = size;
    Pattern Guess = firstGuess[wordLen];
    for (int t = 0; t < 5; t++)
    {
        cout << Guess.dump() << '\n' << flush;
        string score;
        cin >> score;
        int ck = parseScore(score);
        //cerr << "\nV" << setw(8) << valid << " #" 
        //  << setw(3) << t << " : " << Guess.dump()
        //  << " : " << score << "\n";
        if (ck == ~(-1 << wordLen))
        {
            break;
        }
        Guess.filter(ck); 
        Guess = space[proposal(t == 3)];
    }
    // cerr << "\n";

    double time = timer.stopTimer();
    //cerr << setiosflags(ios::fixed) << setprecision(2)
    //   << timer.stopTimer() << " s\n";

    return 0;
}

আমার স্কোর

লিঙ্গোর সাথে মূল্যায়ন, 100 রাউন্ড:

4   9000
5   17700
6   22000
7   25900
8   28600
9   29700
10  31000
11  32800
12  33500
13  34900

মোট 265'100

স্ব-মূল্যবান স্কোর

পুরো ওয়ার্ডলিস্টে স্কোর করা আমার গড় পয়েন্টগুলি এখানে। সম্পূর্ণ নির্ভরযোগ্য নয় কারণ পরীক্ষার সময় অ্যালগরিদমের কিছু বিশদ পরিবর্তন হয়েছে।

 4 # words  6728 PT AVG   100.98 87170.41 s
 5 # words 14847 PT AVG   164.44 42295.38 s
 6 # words 28127 PT AVG   212.27 46550.00 s 
 7 # words 39694 PT AVG   246.16 61505.54 s
 8 # words 49004 PT AVG   273.23 63567.45 s
 9 # words 50655 PT AVG   289.00 45438.70 s
10 # words 43420 PT AVG   302.13 2952.23 s
11 # words 35612 PT AVG   323.62 3835.00 s
12 # words 27669 PT AVG   330.19 5882.98 s
13 # words 19971 PT AVG   339.60 2712.98 s

এই সংখ্যাগুলি অনুসারে, আমার গড় স্কোর 257'800 এর কাছাকাছি হওয়া উচিত

পিট স্কোর

শেষ পর্যন্ত আমি রুবি ইনস্টল করেছি, সুতরাং এখন আমার একটি 'অফিসিয়াল' স্কোর রয়েছে:

    4       5       6       7       8       9      10      11      12      13   TOTAL
10700   16300   22000   25700   27400   30300   32000   33800   34700   34800   267700

আমার উদ্দেশ্য ছিল এরকম কিছু তৈরি করা। হায় আমি কীভাবে সমাধানের জায়গাটি ছোট করতে পারি তা আমি এটি প্রায় অনুমান করেছিলাম। এবং আমার পাইথন এ, তাই এটি এমনকি ধীর, হাহা। আমি প্রথম অনুমানটি হার্ডকোডও করেছি। আপনার চেয়ে কম সংক্ষিপ্ত স্ট্রিংয়ের চেয়ে আমার চেয়ে ভাল। আপনি কি আমার প্রয়োগের সাথে একই সেট ইনপুট তুলনা করতে পরীক্ষা করতে পারেন? এছাড়াও আমাদের প্রথম অনুমানের সেট বেশ আলাদা।
justhalf

@ আসরফাল্ফ আমি লিংগো.গো দিয়ে কিছু রাউন্ড চেষ্টা করেছি। আমি গর্তটি পরীক্ষা করে দেখিনি (আমার কাছে রুবি ইনস্টল নেই)। আমাদের স্কোর খুব কাছে, এটি আমার মনে হয় ভাগ্যের বিষয়।
edc65

আপনার সম্পর্কে আমার মনে হয় ভাল, যেহেতু আমি প্রতিবেদন করা স্কোরের চেয়ে আপনার রিপোর্ট করা গড় ভাল is যদিও আপনি যথেষ্ট বেশি সময় নিচ্ছেন বলে মনে হয়।
জাস্টহেল্ফ

এটি এখন পর্যন্ত সবচেয়ে শক্তিশালী খেলোয়াড় বলে মনে হচ্ছে। আমি আজ পরে অফিসিয়াল ফলাফল চালাতে যাচ্ছি, থাকুন!
স্যারডিয়ারিয়াস

ওফস, উপরের আমার মন্তব্যের জন্য সংশোধন, আমি ভুলে গিয়েছিলাম যে আমার জমাটি জাভাতে রয়েছে।
justhalf

5

জাভা, 249700 পয়েন্ট (আমার পরীক্ষায় চাইনিজ পার্ল গোথকে হারিয়েছে)

আপডেট হওয়া র‌্যাঙ্কলিস্ট:

                        4 5 6 7 8 9 10 11 12 13 মোট
পার্ল চাইনিজ_প্লেল_গোথ.পিএল 6700 12300 16900 19200 23000 26100 28500 29600 32100 33900 228300
জাভা লিঙ্গো 9400 14700 18900 21000 26300 28700 30300 32400 33800 34200 249700

এখানে পুরানো র‌্যাঙ্কলিস্টটি ব্যবহার করে pit.rb:

                        4 5 6 7 8 9 10 11 12 13 মোট
রুবি প্লেয়ার-উদাহরণ.rb 200 400 400 500 1800 1400 1700 1600 3200 4400 15600
রুবি প্লেয়ার-উদাহরণ2.rb 2700 3200 2500 4300 7300 6300 8200 10400 13300 15000 73200
রুবি প্লেয়ার-উদাহরণ3.rb 4500 7400 9900 13700 15400 19000 19600 22300 24600 27300 163700
পার্ল চাইনিজ_প্লেল_গথ.পিএল 6400 14600 16500 21000 22500 26000 27200 30600 32500 33800 231100
জাভা লিঙ্গো 4800 13100 16500 21400 27200 29200 30600 32400 33700 36100 245000

** র‌্যাঙ্কিং **
1: জাভা লিঙ্গো (245000)
2: পার্ল চাইনিজ_পার্ল_গোথ.পিএল (231100)
3: রুবি প্লেয়ার-উদাহরণ3.rb (163700)
4: রুবি প্লেয়ার-উদাহরণ2.rb (73200)
5: রুবি প্লেয়ার-উদাহরণ.rb (15600)

@ চিনিজার্পিলগোথের সাথে তুলনা করে, আমি ছোট শব্দগুলিতে হেরেছি (<rs অক্ষর) তবে আমি দীর্ঘ শব্দে (> = 6 বর্ণ) জিতেছি।

ধারণাটি @ চিনিস্পেরলগোথের অনুরূপ, এটি আমার মূল ধারণাটি অনুমান (এটি একই দৈর্ঘ্যের কোনও শব্দ হতে পারে, অবশিষ্ট সম্ভাব্যতার মধ্যে একটিও নয়) যা পরবর্তী অনুমানের জন্য সর্বাধিক তথ্য দেয়।

বর্তমানে আমি এখনও সূত্রটি নিয়ে খেলছি, তবে উপরের স্কোরবোর্ডের জন্য, আমি এমন শব্দটি বেছে নিচ্ছি যা এর জন্য সর্বনিম্ন ফল দেবে:

-নম_কনফিউশন * এন্ট্রপি

সাম্প্রতিক সংস্করণটি পরবর্তী সেরা অনুমানের জন্য বিভিন্ন স্কোরিং ব্যবহার করে, যা বর্তমান অনুমানের পরে "একক সম্ভাবনা" সংখ্যাটি সর্বাধিক করে তুলছে। সমস্ত সম্ভাব্য প্রার্থীদের ছাঁটাই করা ওয়ার্ডলিস্টে (সময় বাঁচানোর জন্য) সমস্ত শব্দ ব্যবহার করে এটি করা হয়েছে এবং দেখুন যে অনুমানটি "একক সম্ভাবনা" তৈরি করার সম্ভাবনা বেশি (এটি এই অনুমানের পরে কেবল একটি সম্ভাব্য উত্তর থাকবে) পরবর্তী অনুমান

সুতরাং উদাহরণস্বরূপ এই রান:

নতুন দফায় শুরু করা, শব্দটি হ'ল বৈরাগ্য
পেয়েছি: সিওরা
প্রেরিত:? XOXX
পেয়েছি: শীর্ষে
প্রেরিত: XOX? X
পেয়েছি: সন্ন্যাসী
প্রেরিত: XO? XO
পেয়েছি: বেইগ
প্রেরিত: ওএক্সএক্সএক্সএক্স
পেয়েছি: বরনস
প্রেরিত: OOOOO
100 স্কোর দিয়ে রাউন্ড জিতেছে

প্রথম তিনটি অনুমান থেকে আমরা ইতিমধ্যে কোথাও একটি "এন" সহ "* oo * s" পেয়েছি এবং এখনও আমাদের আরও একটি চিঠি বের করতে হবে। এখন এই অ্যালগরিদমের সৌন্দর্যটি হ'ল যে শব্দগুলি সেই রূপের অনুরূপ অনুমান করার পরিবর্তে এটি শব্দের অনুমান করে যা পূর্ববর্তী অনুমানগুলির সাথে মোটেই কোনও সম্পর্ক নেই, আরও চিঠি দেওয়ার চেষ্টা করে, আশাবাদী অনুপস্থিত চিঠিটি প্রকাশ করে। এই ক্ষেত্রে এটি সঠিকভাবে অনুপস্থিত "বি" এর অবস্থান পাওয়ার জন্য ঘটে এবং সঠিক চূড়ান্ত অনুমান "বুনস" দিয়ে শেষ হয়।

কোডটি এখানে:

import java.util.*;
import java.io.*;

class Lingo{
    public static String[] guessBestList = new String[]{
                                "",
                                "a",
                                "sa",
                                "tea",
                                "orae",
                                "seora", // 5
                                "ariose",
                                "erasion",
                                "serotina",
                                "tensorial",
                                "psalterion", // 10
                                "ulcerations",
                                "culteranismo",
                                "persecutional"};
    public static HashMap<Integer, ArrayList<String>> wordlist = new HashMap<Integer, ArrayList<String>>();

    public static void main(String[] args){
        readWordlist("wordlist.txt");
        Scanner scanner = new Scanner(System.in);
        int wordlen = Integer.parseInt(args[0]);
        int roundNum = 5;
        ArrayList<String> candidates = new ArrayList<String>();
        candidates.addAll(wordlist.get(wordlen));
        String guess = "";
        while(roundNum-- > 0){
            guess = guessBest(candidates, roundNum==4, roundNum==0);
            System.out.println(guess);
            String response = scanner.nextLine();
            if(isAllO(response)){
                break;
            }
            updateCandidates(candidates, guess, response);
            //print(candidates);
        }
    }

    public static void print(ArrayList<String> candidates){
        for(String str: candidates){
            System.err.println(str);
        }
        System.err.println();
    }

    public static void readWordlist(String path){
        try{
            BufferedReader reader = new BufferedReader(new FileReader(path));
            while(reader.ready()){
                String word = reader.readLine();
                if(!wordlist.containsKey(word.length())){
                    wordlist.put(word.length(), new ArrayList<String>());
                }
                wordlist.get(word.length()).add(word);
            }
        } catch (Exception e){
            System.exit(1);
        }
    }

    public static boolean isAllO(String response){
        for(int i=0; i<response.length(); i++){
            if(response.charAt(i) != 'O') return false;
        }
        return true;
    }

    public static String getResponse(String word, String guess){
        char[] wordChar = word.toCharArray();
        char[] result = new char[word.length()];
        Arrays.fill(result, 'X');
        for(int i=0; i<guess.length(); i++){
            if(guess.charAt(i) == wordChar[i]){
                result[i] = 'O';
                wordChar[i] = '_';
            }
        }
        for(int i=0; i<guess.length(); i++){
            if(result[i] == 'O') continue;
            for(int j=0; j<wordChar.length; j++){
                if(result[j] == 'O') continue;
                if(wordChar[j] == guess.charAt(i)){
                    result[i] = '?';
                    wordChar[j] = '_';
                    break;
                }
            }
        }
        return String.valueOf(result);
    }

    public static void updateCandidates(ArrayList<String> candidates, String guess, String response){
        for(int i=candidates.size()-1; i>=0; i--){
            String candidate = candidates.get(i);
            if(!response.equals(getResponse(candidate, guess))){
                candidates.remove(i);
            }
        }
    }

    public static int countMatchingCandidates(ArrayList<String> candidates, String guess, String response){
        int result = 0;
        for(String candidate: candidates){
            if(response.equals(getResponse(candidate, guess))){
                result++;
            }
        }
        return result;
    }

    public static String[] getSample(ArrayList<String> words, int size){
        String[] result = new String[size];
        int[] indices = new int[words.size()];
        for(int i=0; i<words.size(); i++){
            indices[i] = i;
        }
        Random rand = new Random(System.currentTimeMillis());
        for(int i=0; i<size; i++){
            int take = rand.nextInt(indices.length-i);
            result[i] = words.get(indices[take]);
            indices[take] = indices[indices.length-i-1];
        }
        return result;
    }

    public static String guessBest(ArrayList<String> candidates, boolean firstGuess, boolean lastGuess){
        if(candidates.size() == 1){
            return candidates.get(0);
        }
        String minGuess = candidates.get(0);
        int wordlen = minGuess.length();
        if(firstGuess && guessBestList[wordlen].length()==wordlen){
            return guessBestList[wordlen];
        }
        int minMatches = Integer.MAX_VALUE;
        String[] words;
        if(lastGuess){
            words = candidates.toArray(new String[0]);
        } else if (candidates.size()>10){
            words = bestWords(wordlist.get(wordlen), candidates, 25);
        } else {
            words = wordlist.get(wordlen).toArray(new String[0]);
        }
        for(String guess: words){
            double sumMatches = 0;
            for(String word: candidates){
                int matches = countMatchingCandidates(candidates, guess, getResponse(word, guess));
                if(matches == 0) matches = candidates.size();
                sumMatches += (matches-1)*(matches-1);
            }
            if(sumMatches < minMatches){
                minGuess = guess;
                minMatches = sumMatches;
            }
        }
        return minGuess;
    }

    public static String[] bestWords(ArrayList<String> words, ArrayList<String> candidates, int size){
        int[] charCount = new int[123];
        for(String candidate: candidates){
            for(int i=0; i<candidate.length(); i++){
                charCount[(int)candidate.charAt(i)]++;
            }
        }
        String[] tmp = (String[])words.toArray(new String[0]);
        Arrays.sort(tmp, new WordComparator(charCount));
        String[] result = new String[size+Math.min(size, candidates.size())];
        String[] sampled = getSample(candidates, Math.min(size, candidates.size()));
        for(int i=0; i<size; i++){
            result[i] = tmp[tmp.length-i-1];
            if(i < sampled.length){
                result[size+i] = sampled[i];
            }
        }
        return result;
    }

    static class WordComparator implements Comparator<String>{
        int[] charCount = null;

        public WordComparator(int[] charCount){
            this.charCount = charCount;
        }

        public Integer count(String word){
            int result = 0;
            int[] multiplier = new int[charCount.length];
            Arrays.fill(multiplier, 1);
            for(char chr: word.toCharArray()){
                result += multiplier[(int)chr]*this.charCount[(int)chr];
                multiplier[(int)chr] = 0;
            }
            return Integer.valueOf(result);
        }

        public int compare(String s1, String s2){
            return count(s1).compareTo(count(s2));
        }
    }
}

দুর্দান্ত, এই এন্ট্রি গুরুতরভাবে শক্তিশালী! আমার মনে আছে টিভি শোতে মানব খেলোয়াড়রা যখন একই চিত্র ব্যবহার করে তখন তারা বর্তমান ক্লু থেকে কোনও শব্দ অনুমান করতে অক্ষম হয়।
স্যারডিয়ারিয়াস

3

পার্ল

উন্নতির জন্য এখনও কিছু জায়গা রয়েছে তবে অন্তত এটি অন্তর্ভুক্ত উদাহরণের খেলোয়াড়দের পরাজিত করে :)

ক্যাচিং ওয়ার্ডলিস্টগুলির জন্য বর্তমান ডিরেক্টরিতে রাইটিং অ্যাক্সেস ধরে নেওয়া (এটি আরও দ্রুত চালিত করতে); wordlist.lenN.storব্যবহার করে ফাইল তৈরি করবে Storable। এটি যদি কোনও সমস্যা হয় তবে সরাতে read_cached_wordlistব্যবহার করতে কোডটি সরিয়ে ফেলুন read_wordlist

ব্যাখ্যা

প্রথমত, আমি বর্তমান ওয়ার্ডলিস্টে ( build_histogram) এর সমস্ত শব্দের মধ্যে অক্ষরের ফ্রিকোয়েন্সিগুলির একটি হিস্টোগ্রাম তৈরি করি । তারপরে আমার আমার পরবর্তী অনুমানটি চয়ন করতে হবে - যা এটি দ্বারা সম্পন্ন হয়েছে find_best_word। স্কোরিং অ্যালগরিদম কেবল হিস্টগ্রামের মানগুলি একসাথে যোগ করছে, ইতিমধ্যে দেখা অক্ষরগুলি এড়িয়ে চলেছে। এটি আমাকে শব্দের তালিকায় সর্বাধিক ঘন অক্ষরযুক্ত একটি শব্দ দেয়। যদি প্রদত্ত স্কোর সহ একাধিক শব্দ থাকে তবে আমি এলোমেলোভাবে একটি বেছে নিই। একটি শব্দ খুঁজে পেয়ে, আমি এটি গেম ইঞ্জিনে প্রেরণ করেছি, উত্তরটি পড়ি তারপরে চেষ্টা করুন এবং এর সাথে দরকারী কিছু করুন :)

আমি শর্তগুলির একটি সেট বজায় রাখি, এটি হ'ল অক্ষর যা কোনও শব্দের মধ্যে একটি নির্দিষ্ট অবস্থানে আসতে পারে। শুরুতে, এটি কেবল সহজ (['a'..'z'] x $len), তবে এটি উত্তরে প্রদত্ত ইঙ্গিতগুলির ভিত্তিতে আপডেট করা হয়েছে (দেখুন update_conds)। আমি তখনকার শর্তগুলির মধ্যে থেকে একটি রেজেক্স তৈরি করি এবং এর মাধ্যমে ওয়ার্ডলিস্ট ফিল্টার করি।

পরীক্ষার সময় আমি জানতে পেরেছি যে পূর্বোক্ত ফিল্টারিং ?খুব ভাল পরিচালনা করে না , সুতরাং দ্বিতীয় ফিল্টার ( filter_wordlist_by_reply)। এটি এই সত্যটির সুবিধা গ্রহণ করে যে ?শব্দের হিসাবে চিহ্নিত একটি চিঠিটি ভিন্ন অবস্থানে দেখা যায় এবং সেই অনুযায়ী শব্দ তালিকাটি ফিল্টার করে।

মূল লুপের প্রতিটি পুনরাবৃত্তির জন্য এই পদক্ষেপগুলি পুনরাবৃত্তি করা হয়, যদি না সমাধান না পাওয়া (বা এটি স্টিডিনের কাছ থেকে আর পড়া সম্ভব হয় না, যার অর্থ ব্যর্থতা)।

কোড

#!perl
use strict;
use warnings;
use v5.10;
use Storable;

$|=1;

sub read_wordlist ($) {
    my ($len) = @_;
    open my $w, '<', 'wordlist.txt' or die $!;
    my @wordlist = grep { chomp; length $_ == $len } <$w>;
    close $w;
    \@wordlist
}

sub read_cached_wordlist ($) {
    my ($len) = @_;
    my $stor = "./wordlist.len$len.stor";
    if (-e $stor) {
        retrieve $stor
    } else {
        my $wl = read_wordlist $len;
        store $wl, $stor;
        $wl
    }
}

sub build_histogram ($) {
    my ($wl) = @_;
    my %histo = ();
    for my $word (@$wl) {
        $histo{$_}++ for ($word =~ /./g);
    }
    \%histo
}

sub score_word ($$) {
    my ($word, $histo) = @_;
    my $score = 0;
    my %seen = ();
    for my $l ($word =~ /./g) {
        if (not exists $seen{$l}) {
            $score += $histo->{$l};
            $seen{$l} = 1;
        }
    }
    $score
}

sub find_best_word ($$) {
    my ($wl, $histo) = @_;
    my @found = (sort { $b->[0] <=> $a->[0] } 
                 map [ score_word($_, $histo), $_ ], @$wl);
    return undef unless @found;
    my $maxscore = $found[0]->[0];
    my @max;
    for (@found) {
        last if $_->[0] < $maxscore;
        push @max, $_->[1];
    }
    $max[rand @max]
}

sub build_conds ($) {
    my ($len) = @_;
    my @c;
    push @c, ['a'..'z'] for 1..$len;
    \@c
}

sub get_regex ($) {
    my ($cond) = @_;
    local $" = '';
    my $r = join "", map { "[@$_]" } @$cond;
    qr/^$r$/
}

sub remove_cond ($$$) {
    my ($conds, $pos, $ch) = @_;
    return if (scalar @{$conds->[$pos]} == 1);
    return unless grep { $_ eq $ch } @{$conds->[$pos]};
    $conds->[$pos] = [ grep { $_ ne $ch } @{$conds->[$pos]} ]
}

sub add_cond ($$$) {
    my ($conds, $pos, $ch) = @_;
    return if (scalar @{$conds->[$pos]} == 1);
    return if grep { $_ eq $ch } @{$conds->[$pos]};
    push @{$conds->[$pos]}, $ch
}

sub update_conds ($$$$) {
    my ($word, $reply, $conds, $len) = @_;
    my %Xes;
    %Xes = ();
    for my $pos (reverse 0..$len-1) {
        my $r = substr $reply, $pos, 1;
        my $ch = substr $word, $pos, 1;

        if ($r eq 'O') {
            $conds->[$pos] = [$ch]
        }

        elsif ($r eq '?') {
            for my $a (0..$len-1) {
                if ($a == $pos) {
                    remove_cond $conds, $a, $ch
                } else {
                    unless (exists $Xes{$a} and $Xes{$a} eq $ch) {
                        add_cond($conds, $a, $ch);
                    }
                }
            }
        }

        elsif ($r eq 'X') {
            $Xes{$pos} = $ch;
            for my $a (0..$len-1) {
                remove_cond $conds, $a, $ch
            }
        }
    }
}

sub uniq ($) {
    my ($data) = @_;
    my %seen; 
    [ grep { !$seen{$_}++ } @$data ]
}

sub filter_wordlist_by_reply ($$$) {
    my ($wl, $word, $reply) = @_;
    return $wl unless $reply =~ /\?/;
    my $newwl = [];
    my $len = length $reply;
    for my $pos (0..$len-1) {
        my $r = substr $reply, $pos, 1;
        my $ch = substr $word, $pos, 1;
        next unless $r eq '?';
        for my $a (0..$len-1) {
            if ($a != $pos) {
                if ('O' ne substr $reply, $a, 1) {
                    push @$newwl, grep { $ch eq substr $_, $a, 1 } @$wl
                }
            }
        }
    }
    uniq $newwl
}

my $len = $ARGV[0] or die "no length";
my $wl = read_cached_wordlist $len;
my $conds = build_conds $len;

my $c=0;
do {
    my $histo = build_histogram $wl;
    my $word = find_best_word $wl, $histo;
    die "no candidates" unless defined $word;
    say $word;
    my $reply = <STDIN>; 
    chomp $reply;
    exit 1 unless length $reply;
    exit 0 if $reply =~ /^O+$/;
    update_conds $word, $reply, $conds, $len;
    $wl = filter_wordlist_by_reply $wl, $word, $reply;
    $wl = [ grep { $_ =~ get_regex $conds } @$wl ]
} while 1

1
আমার বিধিগুলি মূলত ডিস্কে লেখা নিষিদ্ধ করে তবে শব্দ তালিকার
ক্যাচিংয়ের

এই এন্ট্রিটি আমার নিজের (অপ্রকাশিত এখনও) প্রচেষ্টার চেয়ে আরও ভাল কাজ করে। আপনি কি আপনার অ্যালগরিদমকে কিছুটা ব্যাখ্যা করতে পারেন?
স্যারডিয়ারিয়াস

আমি একটি সংক্ষিপ্ত ব্যাখ্যা যোগ করেছি; কোড ফর্ম্যাটিং পাশাপাশি কিছুটা স্থির করে।
চাইনিজ পার্ল গোথ

@ সিরডারিয়াস: আমি মনে করি না যে কোনও নির্দিষ্ট পরীক্ষায় সঠিক দৈর্ঘ্যের কেবলমাত্র প্রবেশিকা রয়েছে এমন কোনও শব্দ তালিকা ব্যবহার করা হলে কোনও ক্ষতি হতে পারে। প্রোগ্রামের পক্ষে ফাইলের মধ্যে যে শব্দগুলির দৈর্ঘ্য নির্দিষ্ট ব্যতীত অন্যথায় রয়েছে তা উপেক্ষা করা অত্যধিক কঠিন হওয়া উচিত নয়, এই জাতীয় শব্দের অস্তিত্ব ন্যূনতম পরীক্ষার গতি কমিয়ে দেয়। এছাড়াও, আমি আশ্চর্য হই যে, যদি একটি শব্দের তালিকা এবং এন দেওয়া হয়, এমন একটি
alচ্ছিক

... এবং মূল প্রোগ্রামটিকে কাঁচা শব্দের তালিকার পরিবর্তে এটি ব্যবহার করার অনুমতি দিন (সুতরাং যদি কিছু প্রাক-বিশ্লেষণ প্রয়োজন হয় তবে প্রতি খেলায় একবারের পরিবর্তে প্রতিটি শব্দ দৈর্ঘ্যের জন্য এটি একবারেই করতে হবে) have
সুপারক্যাট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.