0

これの目的は、合法的な動きの 1 つを選択する前に、どの動きが合法的であるかを理解させることで、Knights Tour をブルート フォースすることでした。私はJavaを初めて使用しますが、この問題の処理方法を理解できないことが私のエラーのように感じます:

import java.util.*;



public class KnightTour
{
    public static void main( String[] args )
    {
    KnightTour kt = new KnightTour(8, 8);
    int tries = 3;
    int tryCount = 0;

    while(tryCount < tries )
    {
        kt.makeMoves();
    }
}

int rows = 0;  //change to args later
int columns = 0;  //change to args later
int tries = 0; //change to args later
String[][] saves;   

int tryCount = 0;
int turnNr = 2;
int wait = 0;

Random rand = new Random();

int xCurrent = 1;
int yCurrent = 1;

int[] xMoves = { 1, 2, -1, -2, 1, 2, -1, -2 };
int[] yMoves = { 2, 1, 2, 1, -2, -1, -2, -1 };

public KnightTour( int x, int y)
{
    rows = x;
    columns = y;
    saves = new String[y][x];

    for (int i = 0; i < y; i++) 
    {
        for (int j = 0; j < x; j++) 
        {
            saves[i][j] = Integer.toString(0);
        }
    }
    saves[0][0] = Integer.toString(1);
}

private void makeMoves()
{
    int k = 0;

    while( k < (rows * columns ) )
    {
        int[] d = { 0, 0, 0, 0, 0, 0, 0, 0 }; // holds move legality
        int i = 0;

        while( i < d.length ) // loop determines which moves are legal
        {
            if( xCurrent + xMoves[ i ] > 0 && xCurrent + xMoves[ i ] < rows )
            {
                if( xCurrent + yMoves[ i ] > 0 && yCurrent + yMoves[ i ] < rows )
                    d[ i ] = 1;
            }
            i++;
        }

        int t = 0;
        int w = 0;

        while( t < d.length ) // checks if no moves are legal
        {   
            if( d[ t ] == 0 )
            {
                w++;
            }
            t++;
        }

        if( w == 8 )
        {
            writeFailures(); // fills the rest of the grid with "x"'s
            k = (rows * columns);  // breaks the loop
        }
        else
        {
            w = 0;
            chooseMove( d );
        }
        k++;
    }
    printSolution();
}

private void chooseMove(int[] d) // chooses a move that was previously determined to be legal randomly and checks if it is available
{
    System.out.println( "trace" );
    Random rand = new Random();
    int r = rand.nextInt(8);
    switch( r )
    {
    case 0:
        if( d[ 0 ] == 1 )
        {
            setX( xCurrent + xMoves[ 0 ] );
            setY( yCurrent + yMoves[ 0 ] );
            saves[yCurrent][xCurrent] = Integer.toString(turnNr);
            turnNr++;
        }
        else
        {
            chooseMove(d);
        }
        break;

    case 1:
        if( d[ 1 ] == 1 )
        {
            setX( xCurrent + xMoves[ 1 ] );
            setY( yCurrent + yMoves[ 1 ] );
            saves[yCurrent][xCurrent] = Integer.toString(turnNr);
            turnNr++;
        }
        else
        {
            chooseMove(d);
        }
        break;

    case 2:
        if( d[ 2 ] == 1 )
        {
            setX( xCurrent +  xMoves[ 2 ] );
            setY( yCurrent + yMoves[ 2 ] );
            saves[yCurrent][xCurrent] = Integer.toString(turnNr);
            turnNr++;
        }
        else
        {
            chooseMove(d);
        }
        break;

    case 3:
        if( d[ 3 ] == 1 )
        {
            setX( xCurrent + xMoves[ 3 ] );
            setY( yCurrent + yMoves[ 3 ] );
            saves[yCurrent][xCurrent] = Integer.toString(turnNr);
            turnNr++;
        }
        else
        {
            chooseMove(d);
        }
        break;

    case 4:
        if( d[ 4 ] == 1 )
        {
            setX( xCurrent + xMoves[ 4 ] );
            setY( yCurrent + yMoves[ 4 ] );
            saves[yCurrent][xCurrent] = Integer.toString(turnNr); // LINE 166
            turnNr++;
        }
        else
        {
            chooseMove(d);
        }
        break;

    case 5:
        if( d[ 5 ] == 1 )
        {
            setX( xCurrent + xMoves[ 5 ] );
            setY( yCurrent + yMoves[ 5 ] );
            saves[yCurrent][xCurrent] = Integer.toString(turnNr);
            turnNr++;
        }
        else
        {
            chooseMove(d);
        }
        break;

    case 6:
        if( d[ 6 ] == 1 )
        {
            setX( xCurrent + xMoves[ 6 ] );
            setY( yCurrent + yMoves[ 6 ] );
            saves[yCurrent][xCurrent] = Integer.toString(turnNr);
            turnNr++;
        }
        else
        {
            chooseMove(d);
        }
        break;

    case 7:
        if( d[ 7 ] == 1 )
        {
            setX( xCurrent + xMoves[ 7] );
            setY( yCurrent + yMoves[ 7 ] );
            saves[yCurrent][xCurrent] = Integer.toString(turnNr);
            turnNr++;
        }
        else
        {
            chooseMove(d);
        }
        break;
    default:
        System.out.println( "error" );
    }
}

public int getX() 
{
    return xCurrent;
}

public void setX(int x) 
{
    xCurrent = x;
}

public int getY() 
{
    return yCurrent;
}

public void setY(int y) 
{
     yCurrent = y;
}

private void writeFailures() // writes an "x" to empty spots in the save array when no legal moves are found
{
    for (int i = 0; i < saves.length; i++) 
    {
        for (int j = 0; j < saves[i].length; j++) 
        {
            if( saves[i][j] == "0");
                saves[i][j] = "x";
        }            
    }
}

private void printSolution()
{
    for (int i = 0; i < saves.length; i++) 
    {
        for (int j = 0; j < saves[i].length; j++) 
        {
            System.out.print(saves[i][j] + " ");
        }
        System.out.println("");
    }
    System.out.println("");
}
}

私が得るエラーは次のとおりです。

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -2
at KnightTour.chooseMove(KnightTour.java:166)
at KnightTour.makeMoves(KnightTour.java:91)
at KnightTour.main(KnightTour.java:14)

編集:これで、コードの行番号は問題ありません。

4

4 に答える 4

0

配列の範囲外エラーは、通常、配列のサイズを超える配列内の格納場所を呼び出そうとしていることを意味します。固定サイズ (たとえば、8 データ ポイント) で配列を宣言した場合、配列 [0] から配列 [7] までの配列値のみを設定および取得できます。

デフォルトでは、配列のカウントは 1 ではなく 0 から始まります。これは、ほとんどの範囲外エラーの原因です。これは、上記の例を参照して、配列 [8] であると想定している最後の要素にアクセスしようとするためです。 .

範囲外エラーを回避する最も簡単な方法は、配列を nil サイズで宣言することです。これにより、必要なサイズに拡張できます。ただし、ランナウェイ コードの場合、メモリ リークのリスクがあります。

于 2012-11-28T06:21:16.410 に答える
0

この行を呼び出すと、問題が発生します(同様の行の1つ)

setY( yCurrent + yMoves[ 4 ] );

yCurrent<0 の場合。これが発生すると、yCurrentは -2 になり ( yMoves[4]=-2 であるため)、次のコード行を呼び出します。

saves[yCurrent][xCurrent] = Integer.toString(turnNr);

<0 であるためyCurrent、存在しない配列インデックスにアクセスしようとしています。したがって、例外です。

さて、このエラーは何度も発生する可能性があります (私のテストでは発生しました)。yCurrent同じ理由で、 (またはxCurrent) が配列サイズ以上の値になった場合にも、同様の効果が発生する可能性があります。

于 2012-11-28T06:22:10.997 に答える
0

バグは、「どの動きが正当かを判断するループ」の上部近くにあります。makeMoves()

この線

if (xCurrent + yMoves[i] > 0 && yCurrent + yMoves[i] < rows)

代わりに

if (yCurrent + yMoves[i] > 0 && yCurrent + yMoves[i] < rows)
于 2012-11-28T06:34:22.280 に答える