多维数组的愚蠢行为

时间:2013-06-23 17:29:39

标签: c++ multidimensional-array tic-tac-toe

问题很简单。我用3X3阵列做了3X3 tictactoe游戏。但问题是:

array[0][3] = array[1][0]

这很奇怪,因为首先,我制作的阵列没有第四列。所以array[0][3]甚至不存在!为了使事情变得复杂,它需要[1][0]

的值

当我输入我的移动的坐标时,我遇到了问题:0 2

void displayBoard(int tictac[3][3])
{
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            cout << tictac[i][j] << " ";
        } cout << "\n" ;
    } cout << "\n";
}



int Horizontal(int x, int y, int tictac[3][3])
{

    if(tictac[x][y+1]==0)
    {
        tictac[x][y+1]=2;
        return 1;
    }

    if(tictac[x][y-1]==0)
    {
        tictac[x][y-1]=2;
        return 1;
    }

    if(tictac[x][y-2]==0)
    {
        tictac[x][y-2]=2;
        return 1;
    }
    if(tictac[x][y+2]==0)
    {
        tictac[x][y+2]=2;
        return 1;
    }

    return 0;
}

int Vertical(int x, int y, int tictac[3][3])
{

    if(tictac[x+1][y]==0)
    {
        tictac[x+1][y]=2;
        return 1;
    }
    if(tictac[x-1][y]==0)
    {
        tictac[x-1][y]=2;
        return 1;
    }
    if(tictac[x-2][y]==0)
    {
        tictac[x-2][y]=2;
        return 1;
    }
    if(tictac[x+2][y]==0)
    {
        tictac[x+2][y]=2;
        return 1;
    }

    return 0;
}

void AI(int X,int Y,int tictac[3][3])
{
    int done = 0;
    cout << "\n-------------------------\nComputer plays: \n";

    done = Horizontal(X,Y,tictac);
    if(done == 0)
    {
    done = Vertical(X,Y,tictac);
    }
}


int main()
{
    int tictac[3][3] = {{0,0,0},{0,0,0}, {0,0,0} };
    int X, Y;
    for(int r=1; r<100; r++)
    {
    cout << "\n-------------------------\nPlayer play a move: \n";
    cin >> X;
    cin >> Y;

    if(tictac[X][Y]==0)
    {
    tictac[X][Y] = 1;
    displayBoard(tictac);
    AI(X,Y,tictac);
    displayBoard(tictac);
    }
    else
    {
        cout << "Space occupied. Try different cell." << endl;
    }


    }





}

2 个答案:

答案 0 :(得分:3)

您需要添加边界检查。例如,当用户输入移动坐标时,您需要确保它们在0到2的范围内。下面的示例验证输入以确保仅输入数字,X和Y坐标都输入到一行中坐标在范围内。它使用std::stringstream来解析坐标,而不必处理检查和清除std::cin上的失败位

#include <string> // at top of your .cpp file
#include <sstream>

// in main()

// Get en entire input line so we can skip extra characters
// after the cell coordinates
string inputLine;
std::getline(cin, inputLine);

stringstream inputStream(inputLine);

if(!(inputStream >> X) || !(inputStream >> Y))
{
    cout << "Please enter the cell coordinates in the form of # #" << endl;
    continue;
}

bool invalidCoordinates = false;

if(X < 0 || X > 2)
{
    cout << "invalid X location" << endl;
    invalidCoordinates = true;
}
if(Y < 0 || Y > 2)
{
    cout << "invalid Y location" << endl;
    invalidCoordinates = true;
}

// check for invalid input
if(invalidCoordinates) continue;

在检查是否可以进行有效移动时,您还需要在VerticalHorizontal函数中执行相同的操作。例如,如果x为2且y为2,则来自Vertical的以下行将访问数组范围之外的数据。

if(tictac[x+1][y]==0)
{
    tictac[x+1][y]=2;
    return 1;
}

这是因为您实际上是使用x+1访问第四个元素。此元素在技术上不存在,但是使用多维数组,您最终会访问tictac[0][y+1]

您可以通过在边缘附加一些填充来填充VerticalHorizontal中的边界,并用一个表示它们不可用的值填充它们。在您的情况下,在每个方向上将大小增加3。

int tictac[9][9] = {
    {3,3,3,3,3,3,3,3,3},
    {3,3,3,3,3,3,3,3,3},
    {3,3,3,3,3,3,3,3,3},
    {3,3,3,0,0,0,3,3,3},
    {3,3,3,0,0,0,3,3,3},
    {3,3,3,0,0,0,3,3,3},
    {3,3,3,3,3,3,3,3,3},
    {3,3,3,3,3,3,3,3,3},
    {3,3,3,3,3,3,3,3,3},
};

您需要适当调整XY,以便他们指向正确的位置。

X += 3;  // Adjust for padding
Y += 3;  // Adjust for padding
if(tictac[X][Y]==0)
{
    tictac[X][Y] = 1;
    displayBoard(tictac);
    AI(X,Y,tictac);
    displayBoard(tictac);
}

您可能需要在代码的其他部分进行调整,但上面的示例应该是您的开始。

您的displayBoard功能也存在问题。打印出阵列ij的元素时,它们会反转,因此电路板会旋转90度。更改以下行

cout << tictac[i][j] << " ";

cout << tictac[j][i] << " ";

另一个问题是您在输出的每一行的末尾使用\n而不使用std::flush来确保将该行发送到控制台。您可以将<< flush;放在之后删除\n并将<< endl;放在该行的末尾。

cout << "\n-------------------------\nComputer plays: \n" << flush;

cout << "\n-------------------------\nComputer plays: " << endl;

以下代码是您问题中包含的原始代码的完整更新。它包含了上述建议,并进行了其他一些更改。我还添加了一个结束游戏,以确定是否还有任何动作。

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

static const int BoardSize = 3;
static const int BoardPadding = BoardSize;
static const int ArraySize = BoardSize + (BoardPadding * 2);

void displayBoard(int tictac[ArraySize][ArraySize])
{
    for(int y = 0; y < BoardSize; y++)
    {
        for(int x = 0; x < BoardSize; x++)
        {
            cout << tictac[BoardPadding + x][BoardPadding + y] << " ";
        }
        cout << endl ;
    }
    cout << endl;
}


int Horizontal(int x, int y, int tictac[ArraySize][ArraySize])
{
    if(tictac[x][y+1]==0)
    {
        tictac[x][y+1]=2;
        return 1;
    }

    if(tictac[x][y-1]==0)
    {
        tictac[x][y-1]=2;
        return 1;
    }

    if(tictac[x][y-2]==0)
    {
        tictac[x][y-2]=2;
        return 1;
    }
    if(tictac[x][y+2]==0)
    {
        tictac[x][y+2]=2;
        return 1;
    }

    return 0;
}


int Vertical(int x, int y, int tictac[ArraySize][ArraySize])
{
    if(tictac[x+1][y]==0)
    {
        tictac[x+1][y]=2;
        return 1;
    }
    if(tictac[x-1][y]==0)
    {
        tictac[x-1][y]=2;
        return 1;
    }
    if(tictac[x-2][y]==0)
    {
        tictac[x-2][y]=2;
        return 1;
    }
    if(tictac[x+2][y]==0)
    {
        tictac[x+2][y]=2;
        return 1;
    }

    return 0;
}


void AI(int X,int Y,int tictac[ArraySize][ArraySize])
{
    int done = 0;
    cout << "\n-------------------------\nComputer plays: " << endl;

    done = Horizontal(X,Y,tictac);
    if(done == 0)
    {
        done = Vertical(X,Y,tictac);
    }
}


// Check if all moves have been made
bool isEndGame(int tictac[ArraySize][ArraySize])
{
    int count = 0;

    for(int y = 0; y < BoardSize; y++)
    {
        for(int x = 0; x < BoardSize; x++)
        {
            count += tictac[BoardPadding + x][BoardPadding + y] ? 1 : 0;
        }
    }

    return count == (BoardSize * BoardSize);
}


int main()
{
    int tictac[ArraySize][ArraySize] = {
        {3,3,3,3,3,3,3,3,3},
        {3,3,3,3,3,3,3,3,3},
        {3,3,3,3,3,3,3,3,3},
        {3,3,3,0,0,0,3,3,3},
        {3,3,3,0,0,0,3,3,3},
        {3,3,3,0,0,0,3,3,3},
        {3,3,3,3,3,3,3,3,3},
        {3,3,3,3,3,3,3,3,3},
        {3,3,3,3,3,3,3,3,3},
    };
    int X, Y;

    while(isEndGame(tictac) == false)
    {
        cout << "\n-------------------------\nPlayer play a move: " << flush;

        // Get en entire input line so we can skip extra characters
        // after the cell coordinates
        string inputLine;
        std::getline(cin, inputLine);

        stringstream inputStream(inputLine);

        if(!(inputStream >> X) || !(inputStream >> Y))
        {
            cout << "Please enter the cell coordinates in the form of # #" << endl;
            continue;
        }

        bool invalidCoordinates = false;

        if(X < 0 || X >= BoardSize)
        {
            cout << "invalid X location" << endl;
            invalidCoordinates = true;
        }
        if(Y < 0 || Y >= BoardSize)
        {
            cout << "invalid Y location" << endl;
            invalidCoordinates = true;
        }

        // check for invalid input
        if(invalidCoordinates) continue;

        // adjust the coordinates and do our thing
        X += BoardPadding;
        Y += BoardPadding; 
        if(tictac[X][Y]==0)
        {
            tictac[X][Y] = 1;
            displayBoard(tictac);
            AI(X,Y,tictac);
            displayBoard(tictac);
        }
        else
        {
            cout << "Space occupied. Try different cell." << endl;
        }
    }

    cout << "game finished...check for winner" << endl;
}

注意:使用using namespace std;是个坏主意。它将所有内容从std命名空间提取到当前范围(在本例中为全局命名空间),并可能导致冲突。最好使用完全限定的名称,例如std::cout来避免这种情况。

答案 1 :(得分:1)

如果是这个数组

int array[3][3];

以下声明有效

array[0][3] == array[1][0]

,因为:

  • C / C ++不执行任何边界检查。
  • 3x3阵列存储为1D阵列。当您指定2D索引时,编译器会将它们转换为1D索引:[j][i]变为[j * width + i]
  • 因此,array[0][3]指向内存中的0 * 3 + 3(第三个)单元格,但array[1][0]指向内存的1 * 3 + 0(也是第三个!)单元格,从2D阵列的开始。