HitAndBlow

ADPの開発が滞っていますが、思わぬところで話が進んでしまい、今年最後の記事になります。

社会人であり、技術者でありのコメント欄で結合について話が盛り上がったのですが、『私がHitAndBlowを作ったらどんなコードになるか?』ということで作成してみました。Visual C++ 2008で動作確認しました。
επιστημηさんの真似だと芸がないので、出題者・回答者をそれぞれ人間・コンピュータから選べるようにしました(大掃除をさぼったので嫁に怒られながら作りました・・・)。

それにしてもC++のコードは人によって個性が出ますね。


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <math.h>
#include <ctype.h>
#include <time.h>

using namespace std;

class HABReferee {
    vector<int>     answer;
    vector<bool>    blowtable;
public:
    bool prepareAnswer(const vector<int> &answer_) {
        blowtable.assign(10, false);
        for ( size_t i = 0; i < answer_.size(); i++ ) {
            if ( blowtable[answer_[i]] ) {
                return false;
            }
            blowtable[answer_[i]] = true;
        }
        answer = answer_;
        return true;
    }

    bool submitAnswer( const vector<int> submit, int &hit, int &blow) {
        if ( answer.size() != submit.size() ) return false;
        hit = 0;
        blow = 0;
        for ( size_t i = 0; i < submit.size(); i++ ) {
            if ( answer[i] == submit[i] ) {
                hit++;
            } else if ( blowtable[submit[i]] ) {
                blow++;
            }
        }
        return hit == submit.size();
    }
};

static vector<int> inputNumbers(int N) { // N桁の数値の入力を行う(違った場合はやり直し)
    vector<int> result;
    string str;
    do {
        result.clear();
        cin >> str;
        for ( size_t i = 0; i < str.size(); i++ ) {
            if ( isdigit(str[i]) && str[i] != '0' )
                result.push_back(str[i] - '0');
            else
                break;
        }
    } while ( result.size() != N );
    return result;
}

class HABContributor {    // 出題者(人間)
public:
    virtual vector<int> prepareAnswser(int N) {
        cout << "各桁が1~9である" << N << "桁の数を入力してほしい。各桁で数が重複するのは避けてくれ" << endl;
        return inputNumbers(N);
    }
};

class HABContriburerComputer : public HABContributor {    // 出題者(乱数生成)
public:
    virtual vector<int> prepareAnswser(int N) {
        vector<int> digits;
        for ( int i = 1; i < 10; i++ ) {
            digits.push_back(i);
        }
        vector<int> result;
        srand((unsigned int)time(0));
        for ( int i = 0; i < N; i++ ) {
            vector<int>::iterator itor = digits.begin() + rand() % digits.size();
            result.push_back(*itor);
            digits.erase(itor);
        }
        return result;
    }
};


class HABSolver {    // 回答者(人間)
public:
    virtual void prepare(int N) {}

    virtual vector<int> getAnswer(int N) {
        cout << "答えを予想してくれ" << N << "桁の数だ。" << endl;
        return inputNumbers(N);
    }

    virtual void giveHint( int hit, int blow) {
        cout << hit << "Hit" << " / " << blow << "blow" << endl;
    }
};

class HABSolverComputer : public HABSolver {    // 回答者(コンピューター)
    HABReferee           checker;
    vector<vector<int>>  candidate;
public:
    void recur(vector<int> &answer, int N) {
        if ( N == 0 ) {
            candidate.push_back(answer);
        } else {
            for ( int i = 1; i < 10; i++ ) {
                if ( find( answer.begin(), answer.end(), i) == answer.end() ) {
                    answer.push_back(i);
                    recur( answer, N-1);
                    answer.pop_back();
                }
            }
        }
    }
    virtual void prepare(int N) {
        vector<int> answer;
        recur( answer, N);
    }

    virtual vector<int> getAnswer(int N) {
        cout << "答えは";
        for ( int i = 0; i < N; i++ ) {
            cout << candidate.back()[i];
        }
        cout << "かな?";
        return candidate.back();
    }

    virtual void giveHint( int hit, int blow) {
        HABSolver::giveHint( hit, blow);
        checker.prepareAnswer(candidate.back());
        for ( vector<vector<int>>::iterator i = candidate.begin(); i < candidate.end(); ) {
            int ahit, ablow;
            checker.submitAnswer( *i, ahit, ablow);
            if ( ahit != hit || ablow != blow ) {
                i = candidate.erase(i);
            } else {
                i++;
            }
        }

    }
};

class HABGame {
    int        N;
    HABReferee       referee;
    HABContributor   *c;
    HABSolver        *s;
public:
    HABGame(int N_, HABContributor *c_, HABSolver *s_) : N(N_), c(c_), s(s_) {};
    void play() {
        // 出題者から問題をもらいレフリーに渡す。
        while ( !referee.prepareAnswer(c->prepareAnswser(N)) )
            ; // 規格にあったものが出てくるまでループする

        bool endflag = false;
        int hit;
        int blow;
        s->prepare(N);    // 回答者に準備をさせる
        while ( endflag == false ) {
            // 回答者から回答をもらい判定する。
            endflag = referee.submitAnswer( s->getAnswer(N), hit, blow);
            // 回答者にヒントを言う。
            s->giveHint( hit, blow);
        }
    }
};

int main()
{
    HABContributor           hc;
    HABContriburerComputer   cc;
    HABSolver                hs;
    HABSolverComputer        cs;
    HABContributor           *c;
    HABSolver                *s;

    string    str;
    while ( true ) {
        cout << "メニュー" << endl
             << "1:出題者(Human) vs 回答者(Human)" << endl
             << "2:出題者(Human) vs 回答者(Computer)" << endl
             << "3:出題者(Computer) vs 回答者(Human)" << endl
             << "4:出題者(Computer) vs 回答者(Computer)" << endl
             << "0:終了" << endl;
        cin >> str;
        switch( str[0] ) {
            case '0' :
                return 0;
            case '1' :
                c = &hc;
                s = &hs;
                break;
            case '2' :
                c = &hc;
                s = &cs;
                break;
            case '3' :
                c = &cc;
                s = &hs;
                break;
            case '4' :
                c = &cc;
                s = &cs;
                break;
        }
        HABGame g(3, c, s);
        g.play();
    }

    return 0;
}
2012-12-31 | コメント:0件

コメントをどうぞ


『不適切なコメントへの対応』を一読下さい。
現在コメントは承認制となっております。

Previous Page | Next Page