javaknights-tour

Method call within an array statement causing program to "hang"


I have written a program based on trying to solve the Knight’s Tour problem. I believe I have come up with an appropriate solution and everything looks fine.

The small issue I am curious about is with a small section of code which implements the best move based on looking ahead to future possible squares.

If I implement it like this (implementation1)–

if( moveMade )  // if any move is possible
{
    currentRow += vertical[ betterMove( valueMatrix, horizontal, vertical, accessibility, currentRow, currentColumn ) ];
    currentColumn += horizontal[ betterMove( valueMatrix, horizontal, vertical, accessibility, currentRow, currentColumn ) ];
    board[ currentRow ][ currentColumn ] = squareCounter;
    squareCounter++;
    moveMade = false;
}
else
moveMade = true;    // if there are no moves possible this is the end

the software will hang – why?

If I make a small innocuous and seemingly trivial change such as this (implementation2) –

int temp1 = betterMove( valueMatrix, horizontal, vertical, accessibility, currentRow, currentColumn );

if( moveMade )  // if any move is possible
{
    currentRow += vertical[ temp1 ];
    currentColumn += horizontal[ temp1 ];
    board[ currentRow ][ currentColumn ] = squareCounter;
    squareCounter++;
    moveMade = false;
}
else
    moveMade = true;    // if there are no moves possible this is the end

then everything is fine and the code will reach its conclusion.

I’m using netbeans 7.1 to write my software and thought it must be something to do with the IDE so I tried to compile it using just ‘javac’ and the command line only to find the same results. I don’t understand why I can’t make this method call within the array parameter like this – vertical[ HERE ] or horizontal[ HERE ] and have the result which returns used in the expression. I’ve managed to code like this before without any problem.

Here is the method being called –

public static int betterMove( int moverMatrix[], int theHorizontal[], int theVertical[], int accessBoard[][], int newCurrentRow, int newCurrentColumn )
{
    int[] equalMatrix = new int [ 8 ];  // records the positions which are equal in value with a (1)
    int[] bmValueMatrix = new int[ 8 ]; // holds the numbers taken from accessibility heuristic
    int[] finalTable = new int[ 8 ];    // the best move discovered
    int best = bestMove( moverMatrix ); // the lowest number in the given array
    int startPos = best + 1;
    int moveNumber = 0;
    int originalCurrentRow = newCurrentRow;
    int originalCurrentColumn = newCurrentColumn;

    equalMatrix[ best ] = 1;    // mark the lowest value position with a 1

    initVMatrix( bmValueMatrix );
    initVMatrix( finalTable );

    for( int i = startPos; i < 8; i++ ) // mark the elements of equal value in equalMatrix with (1)
    {
        if( moverMatrix[ best ] == moverMatrix[ i ] )
            equalMatrix[ i ] = 1;
    }

    for( int j = 0; j < 8; j++ )    // go through each element of equalMatrix and look forward
    {                               // for best accessibility heuristic
        newCurrentRow = originalCurrentRow;
        newCurrentColumn = originalCurrentColumn;
        if( equalMatrix[ j ] == 1 )
        {
            newCurrentRow += theVertical[ j ];
            newCurrentColumn += theHorizontal[ j ];
            while( moveNumber < 8 )
            {
                if( newCurrentRow + theVertical[ moveNumber ] >= 0 &&
                        newCurrentRow + theVertical[ moveNumber ] < 8 )
                {
                    if( newCurrentColumn + theHorizontal[ moveNumber ] >= 0 &&
                            newCurrentColumn + theHorizontal[ moveNumber ] < 8 )
                    {
                        bmValueMatrix[ moveNumber ] = accessBoard[ newCurrentRow + theVertical[ moveNumber ] ]
                                                                    [ newCurrentColumn + theHorizontal[ moveNumber ] ]; 
                    }   // end if
                }   // end if
                moveNumber++;
            }   // end while 
            moveNumber = 0;
            finalTable[ j ] = bestMove( bmValueMatrix );
            initVMatrix( bmValueMatrix );
        }   // end if

    }   // end for
    return bestMove( finalTable );   
}

The method bestmove used in the return statement above -

public static int bestMove( int theMoves[] )
{
    int theLowest = 10,
        idealMove = 0;

    for( int i = 0; i < 8; i++ )
    {
        if( theMoves[ i ] < theLowest )
        {
            theLowest = theMoves[i];
            idealMove = i;
        }
    }
    return idealMove;
}

Solution

  • currentRow += vertical[ betterMove( valueMatrix, horizontal, vertical, accessibility, currentRow, currentColumn ) ];
    currentColumn += horizontal[ betterMove( valueMatrix, horizontal, vertical, accessibility, currentRow, currentColumn ) ];
    

    In the above case, index value for both the arrays are not same.

    The problem is, by the time you invoke the betterMove method the second time, the currentRow value has changed and as you are passing currentRow in your method as one of the paramters, so, the index that is used for horizontal array, is not the same as the one that would be used when you invoke the method outside your if (moveMade).

    Note, the difference is only for the 2nd statement. First one will be same as in both the ways.

    So, that might be a problem.

    So, you need to first store the return value of the execution of that method, and then use that return value as the index of both vertical and horizontal array.

    int temp1 = betterMove( valueMatrix, horizontal, vertical, accessibility, currentRow, currentColumn );
    
    if( moveMade )  // if any move is possible
    {
        currentRow += vertical[ temp1 ];
        currentColumn += horizontal[ temp1 ];
        // Rest of the code
    }
    

    Now in this case, both the arrays have same index value - temp1.

    Also, if you are using the return value of a method call more than one time, and that method is modifying any of your passed parameter, you should always invoke the method one time, and store the return value, and use it rather. This will save you from witnessing weird results.