2

多次元配列に基づいた基本的な三目並べゲームを作成しました。g[3][3]。私のプログラムでは、これから紹介する条件のように、約9つの条件があります。

if((g[0][0] == X && g[0][1] == X && g[0][2] == X) || (g[0][0] == O && g[0][1] == O && g[0][2] == O))

これは非常に正気ではありません。私はおそらく何か間違ったことをしているのですが、これが私がこの質問に取り組んでいる理由です。このような長くて複雑な状態を表現する簡単な方法はありますか?たとえば、どういうわけか私はできませんでした:

if(grid.hasXes)
4

9 に答える 9

6

あなたはおそらくそれについて間違った方法で行っているでしょう。可能な組み合わせは3^9、つまり19683しかないためint、16ビットマシンでもグリッドをに変換できます。

int
asInt( char const (&grid)[3][3] )
{
    int results = 0;
    for ( int i = 0; i != 3; ++ i ) {
        for ( int j = 0; j != 3; ++ j ) {
            results *= 3;
            switch ( grid[i][j] ) {
            case 'X':
                results += 1;
                break;

            case 'Y':
                results += 2;
                break;

            case ' ':
                break;

            default:
                assert(0);
            }
        }
    }
    return results;
}

その後、intを使用して、誰が勝ったか(誰かがいる場合)を示すテーブルにインデックスを付けることができます。または、一方または他方のプレーヤーの位置を9ビット整数に変換することもできます。

int
asInt( char const (&grid)[3][3], char who )
{
    int results = 0;
    for ( int i = 0; i != 3; ++ i ) {
        for ( int j = 0; j != 3; ++ j ) {
            results *= 2;
            if ( grid[i][j] == who ) {
                ++ results;
            }
        }
    }
    return results;
}

次に、テーブルへの単純な線形検索を使用して、必要なビットが設定されていることを確認できます。

static int const wins[] =
{
    0007, 0070, 0700,       //  rows
    0111, 0222, 0444,       //  columns
    0124, 0421              //  diagonals
};

class Wins
{
    int myToMatch;
public:
    Wins( char const (&grid)[3][3], char who )
        : myToMatch( asInt( grid, who ) )
    {
    }
    bool operator()( int entry ) const
    {
        return (entry & myToMatch) == entry;
    }
};

それで:

if ( std::find_if( begin( wins ), end( wins ), Wins( grid, 'X' ) )
            != end( wins ) {
    //  X wins
else if ( std::find_if( begin( wins ), end( wins ), Wins( grid, 'O' ) )
            != end( wins ) {
    //  O wins
else
    //  play another turn.

intグリッドをプレーヤーごとに1つずつ、2つとして維持することも検討できます。位置のビット番号はであり3 * i + j、移動が合法であるかどうかをテストするには、次のようにします。

bool
isLegal( int gridX, int gridY, int i, int j )
{
    return ((gridX | gridY) & (1 << (3 * i + j))) == 0;
}
于 2012-04-16T15:37:40.327 に答える
4

この種の問題に対処する最も簡単で最も強力な方法は、醜いコードを関数に抽出することです。その関数は、便利な場合はクラスのメンバーにすることも、単に無料の関数にすることもできます。あなたの場合、クイックフィックスは次のようになります

bool hasXes(char[3][3] g) {
    return (g[0][0] == X && g[0][1] == X && g[0][2] == X) || (g[0][0] == O && g[0][1] == O && g[0][2] == O)
}

次に、次のように書くことができます。

if (hasXes(g)) ...
于 2012-04-16T14:03:35.953 に答える
3

今私はそれを手に入れました...

bool check(char *g, int x, int y, int moveX, int moveY, char ch)
{
    for (int i(0); i<3; ++i)
    {
        if ((g+(y*3)+x) != ch) return false;
        x += moveX;
        y += moveY;
    }
    return true;
}

あなたはそれをそのように使います:

if (check(g, 0, 0, 0, 1, 'O')) //checking O in the first row.
if (check(g, 0, 0, 0, 1, 'X')) //checking X in the first row.
if (check(g, 0, 0, 1, 0, 'O')) //checking O in the first column.
if (check(g, 0, 0, 1, 0, 'X')) //checking X in the first column.
于 2012-04-16T14:03:20.093 に答える
2

複雑さを隠し、メインのドライバー関数の可読性を高める関数を書くことができます。たとえば、行または列をチェックして、すべてがXまたはOに等しいかどうかを確認できます。

于 2012-04-16T14:03:21.163 に答える
1

これは機能するはずです:

bool found = false;
int i, j;
for(i = 0; i < 3; i++)
{
    for(j = 0; j < 3; j++)
    {
        if(g[i][j] == X)
        {
            found = true;
            break;
        }
    }
    if(found == true)
    {
        break;
    }
}
if(found == true)
{
    // do something because one of them had X.  i, j have the co-ordinates of the first find of it
}
else
{
    // none of them had X
}

gotoを使用する方法もあるかもしれませんが、c++ではあまり推奨されていません。一度に1行だけが必要な場合は、1つのループのみを使用してください。

于 2012-04-16T14:07:06.540 に答える
0

この特殊なケースでは、やや単純な比較もあります。

if(g[0][0] == g[0][1] && g[0][1] == g[0][2])

少なくとも、存在する可能性があるXと仮定しOます。そうでなければ、これはになります

if(g[0][0] == g[0][1] && g[0][1] == g[0][2] && ( g[0][1] == X || g[0][1] == O ) )

これはまだはるかに単純な私見です。

このように単純化できない場合は、他の人が指摘しているようにループを使用してください。

于 2012-04-16T14:31:12.170 に答える
0

から選択するもう1つのオプション。ストレージが隣接している場合は、memcmpを使用できます

if(!memcmp(g[0],"XXX",3) || !memcmp(g[0],"OOO",3))
于 2012-04-16T14:11:31.697 に答える
0

Xを数えるか、それらを見つけようとすることができます。

gが3x3の配列であり、文字XまたはO:を含むと仮定します。

char* end = g + 9;
std::count(g, end, 'X') > 0;

またはより効率的に:

char* end = g + 9;
std::find(g, end, 'X') != end;
于 2012-04-16T14:16:18.630 に答える
0

タイプセーフなコメント!

const bool first_is_xful = g[0][0] == X && g[0][1] == X && g[0][2] == X,
           second_is_xful = ...;

if (first_is_xful || second_is_xful || ...) ...

または関数関数:

bool is_xful (int row, ...) ...

...

if (is_ixful(0) || ...
于 2012-04-16T15:20:17.853 に答える