第58章 357の山 その2


今回は、必勝法もどきを使ってコンピュータを無敵(?)状態にします。 これは、C言語編第77章のC++版です。 必勝パターンに持ち込む方法C言語版と全く同じです。



では、早速プログラムを見てみましょう。

// game35702.cpp

#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

class Mountain
{
    int mt[3];
    int sente, order;
    int judge();
    int show_stone();
    int init();
    int take_stone();
    int comp_take();
    int no_of_0();
public:
    int play();
};
Mountainクラスにno_of_0メンバ関数が増えました。これは、石の数が0である 山の数を返します。
int Mountain::show_stone()
{
    cout << "[A]---" << mt[0] << ", [B]---" << mt[1] << ", [C]---" << mt[2] << endl;
    return 0;
}

int Mountain::judge()
{
    if (mt[0] + mt[1] + mt[2] == 1)
        return 0;
    else
        return 1;
}

int Mountain::take_stone()
{
    char ans[8];
    int stone, mtorder;
    
    if (sente != order) {
        comp_take();
        if (judge() == 0) {
            cout << "コンピュータの勝ちです" << endl;
            return 1;
        }
        if (order == 1)
            order = 0;
        else
            order = 1;
        return 0;
    }

    while (1) {
        cout << "どの山からとりますか(A,B,C)---";
        cin >> ans;
        if (strcmp(ans, "A") != 0 && strcmp(ans, "B") != 0 && strcmp(ans, "C") != 0 &&
            strcmp(ans, "a") != 0 && strcmp(ans, "b") != 0 && strcmp(ans, "c") != 0) {
            cout << "山の指定が正しくありません" << endl;
            continue;
        } else {
            ans[0] = toupper(ans[0]);
            mtorder = ans[0] - 'A';
            if (mt[mtorder] == 0) {
                cout << "その山にはもう石はありません" << endl;
                continue;
            }
            break;
        }
    }
    
    while (1) {
        cout << "いくつとりますか---";
        cin >> ans;
        stone = atoi(ans);
        mt[mtorder] -= stone;
        if (mt[0] + mt[1] + mt[2] == 0) {
            cout << "その取り方では山の石が全部0になります" << endl;
            mt[mtorder] += stone;
            continue;
        }
        mt[mtorder] += stone;
        if (mt[mtorder] - stone < 0 || stone <= 0) {
            cout << "取る石の数が不正です" << endl;
            continue;
        } else {
            break;
        }
    }
    mt[mtorder] -= stone;
    show_stone();
    if (judge() == 0) {
        cout << "あなたの勝ちです" << endl;
        return 1;
    }
        
    if (order == 1)
        order = 0;
    else
        order = 1;

    return 0;
}

int Mountain::init()
{
    char ans[8];

    mt[0] = 3;
    mt[1] = 5;
    mt[2] = 7;

    cout << "あなたが先手になりますか(Y/N)---";
    cin >> ans;

    if (ans[0] == 'y' || ans[0] == 'Y') {
        sente = 1;
    } else {
        sente = 0;
    }
    order = 1;
    return 0;
}
これらのメンバ関数に変更はありません。
int Mountain::comp_take()
{
    int mtorder, stone;
    char mtname;
    int jump = 0, i;


    srand((unsigned)time(NULL));
    
    if (no_of_0() == 0) { //どの山も0ではない
        //2-4-6パターンにする
        if (mt[0] == 3 && mt[1] == 4 && mt[2] == 6) {
            mtorder = 0;
            stone = 1;
            mt[0] = 2;
            goto end;
        }
        if (mt[1] == 5 && mt[0] == 2 && mt[2] == 6) {
            mtorder = 1;
            stone = 1;
            mt[1] = 4;
            goto end;
        }
        if (mt[2] == 7 && mt[0] == 2 && mt[1] == 4) {
            mtorder = 2;
            stone = 1;
            mt[2] = 6;
            goto end;
        }
        //1-4-5パターンにする
        if (mt[0] > 1 && mt[1] + mt[2] == 9 && mt[1] * mt[2] == 20) {
            mtorder = 0;
            stone = mt[0] - 1;
            mt[0] = 1;
            goto end;
        }
        if (mt[1] > 4 && mt[0] == 1 && mt[2] == 5) {
            mtorder = 1;
            stone = mt[1] - 4;
            mt[1] = 4;
            goto end;
        }
        if (mt[2] > 4 && mt[0] == 1 && mt[1] == 5) {
            mtorder = 2;
            stone = mt[2] - 4;
            mt[2] = 4;
            goto end;
        }
        if (mt[2] > 5 && mt[0] == 1 && mt[1] == 4) {
            mtorder = 2;
            stone = mt[2] - 4;
            mt[2] = 4;
            goto end;
        }
        //1-2-3パターンにする
        if (mt[0] > 1 && mt[1] + mt[2] == 5 && mt[1] * mt[2] == 6) {
            mtorder = 0;
            stone = mt[0] - 1;
            mt[0] = 1;
            goto end;
        }
        if (mt[0] > 2 && mt[1] + mt[2] == 4 && mt[1] * mt[2] == 3) {
            mtorder = 0;
            stone = mt[0] - 2;
            mt[0] = 2;
            goto end;
        }
        if (mt[0] == 3 && mt[1] + mt[2] == 3 && mt[1] * mt[2] == 2) {
            mtorder = 0;
            stone = mt[0] - 3;
            mt[0] = 3;
            goto end;
        }
        if (mt[1] > 1 && mt[0] + mt[2] == 5 && mt[0] * mt[2] == 6) {
            mtorder = 1;
            stone = mt[1] - 1;
            mt[1] = 1;
            goto end;
        }
        if (mt[1] > 2 && mt[0] + mt[2] == 4 && mt[0] * mt[2] == 3) {
            mtorder = 1;
            stone = mt[1] - 2;
            mt[1] = 2;
            goto end;
        }
        if (mt[1] > 3 && mt[0] + mt[2] == 3 && mt[0] * mt[2] == 2) {
            mtorder = 1;
            stone = mt[1] - 3;
            mt[1] = 3;
            goto end;
        }
        if (mt[2] > 1 && mt[0] + mt[1] == 5 && mt[0] * mt[1] == 6) {
            mtorder = 2;
            stone = mt[2] - 1;
            mt[2] = 1;
            goto end;
        }
        if (mt[2] > 2 && mt[0] + mt[1] == 4 && mt[0] * mt[1] == 3) {
            mtorder = 2;
            stone = mt[2] - 2;
            mt[2] = 2;
            goto end;
        }
        if (mt[2] > 3 && mt[0] + mt[1] == 3 && mt[0] * mt[1] == 2) {
            mtorder = 2;
            stone = mt[2] - 3;
            mt[2] = 3;
            goto end;
        }
        //1-1-1パターンにする
        if (mt[0] == mt[1] && mt[0] == 1 && mt[2] > 1) {
            mtorder = 2;
            stone = mt[2] - 1;
            mt[2] = 1;
            goto end;
        }
        if (mt[1] == mt[2] && mt[1] == 1 && mt[0] > 1) {
            mtorder = 0;
            stone = mt[0] - 1;
            mt[0] = 1;
            goto end;
        }
        if (mt[0] == mt[2] && mt[0] == 1 && mt[1] > 1) {
            mtorder = 1;
            stone = mt[1] - 1;
            mt[1] = 1;
            goto end;
        }
        if (mt[0] == mt[1]) {
            mtorder = 2;
            stone = mt[2];
            mt[mtorder] = 0;
            goto end;;
        }
        if (mt[1] == mt[2]) {
            mtorder = 0;
            stone = mt[0];
            mt[mtorder] = 0;
            goto end;;
        }
        if (mt[2] == mt[0]) {
            mtorder = 1;
            stone = mt[1];
            mt[mtorder] = 0;
            goto end;;
        }
    }

    //0の山が1つだけである
    if (no_of_0() == 1) {
        if (mt[0] == 0) {
            if (mt[1] == 1) {
                mtorder = 2;
                stone = mt[2];
                mt[2] = 0;
                goto end;
            }
            if (mt[2] == 1) {
                mtorder = 1;
                stone = mt[1];
                mt[1] = 0;
                goto end;
            }

            if (mt[1] > mt[2]) {
                mtorder = 1;
                stone = mt[1] - mt[2];
                mt[mtorder] -= stone;
                goto end;
            }
            if (mt[2] > mt[1]) {
                mtorder = 2;
                stone = mt[2] - mt[1];
                mt[mtorder] -= stone;
                goto end;
            } 
            if (mt[2] == mt[1]){
                mtorder = 1;
                stone = 1;
                mt[mtorder] -= stone;
                goto end;
            }
        }
        if (mt[1] == 0) {
            if (mt[0] == 1) {
                mtorder = 2;
                stone = mt[2];
                mt[2] = 0;
                goto end;
            }
            if (mt[2] == 1) {
                mtorder = 0;
                stone = mt[0];
                mt[0] = 0;
                goto end;
            }
            if (mt[0] > mt[2]) {
                mtorder = 0;
                stone = mt[0] - mt[2];
                mt[mtorder] -= stone;
                goto end;
            }
            if (mt[2] > mt[0]) {
                mtorder = 2;
                stone = mt[2] - mt[0];
                mt[mtorder] -= stone;
                goto end;
            }
            if (mt[0] == mt[2]) {
                mtorder = 2;
                stone = 1;
                mt[mtorder] -= stone;
                goto end;
            }
        }
        if (mt[2] == 0) {
            if (mt[1] == 1) {
                mtorder = 0;
                stone = mt[0];
                mt[0] = 0;
                goto end;
            }
            if (mt[0] == 1) {
                mtorder = 1;
                stone = mt[1];
                mt[1] = 0;
                goto end;
            }
            if (mt[0] > mt[1]) {
                mtorder = 0;
                stone = mt[0] - mt[1];
                mt[mtorder] -= stone;
                goto end;
            }
            if (mt[1] > mt[0]) {
                mtorder = 1;
                stone = mt[1] - mt[0];
                mt[mtorder] -= stone;
                goto end;
            }
            if (mt[1] == mt[0]) {
                mtorder = 0;
                stone = 1;
                mt[mtorder] -= 1;
                goto end;
            }
        }
    }

    if (no_of_0() == 2) {
        for (i = 0; i < 3; i++) {
            if (mt[i] != 0) {
                stone = mt[i] - 1;
                mtorder = i;
                mt[i] = 1;
                goto end;
            }
        }
    }
    while (1) {
        mtorder = rand() % 3;
        if (mt[mtorder] == 0)
            continue;
        else
            break;
    }
    while (1) {
        stone = 1;
        mt[mtorder] -= stone;
        if (mt[0] + mt[1] + mt[2] == 0) {
            mt[mtorder] += stone;
            continue;
        } else {
            break;
        }
    }
end:
    mtname = mtorder + 'A';
    cout << "コンピュータは" << mtname << "から" << stone << "個取りました" << endl;
    show_stone();
    return 0;
}
コンピュータが取る石を決定するメンバ関数です。具体的考え方は C言語編第77章を参照してください。
int Mountain::play()
{
    int ret;
    char ans[8];

    while (1) {
        init();
        show_stone();
        while (1) {
            ret = take_stone();
            if (ret == 1)
                break;
        }
        cout << endl << "もう一度やりますか(Y/N)";
        cin >> ans;
        if (ans[0] == 'y' || ans[0] == 'Y')
            continue;
        else
            break;
    }
    return 0;
}
このメンバ関数に変更はありません。
int Mountain::no_of_0()
{
    int no, i;

    no = 0;
    for (i = 0; i < 3; i++) {
        if (mt[i] == 0)
            no++;
    }
    return no;
}
石の数が0である山の数を返す関数です。特に説明は不要ですね。
int main()
{
    Mountain m;
    
    m.play();
    return 0;
}
main関数はいつもと同じです。

今回のプログラムでは、コンピュータは相当強くなったはずです。 必勝法もどきを知らない人と対戦するとまず100%コンピュータが勝つはずです。

対戦中、石の数を「○」で表示するなど、視覚に訴えられるように改良してみてください。


[C++Index] [総合Index] [Previous Chapter] [Next Chapter]

Update Apr/29/2002 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。