Plotting the Knight’s Next Move


The next step in hopping a knight around a chessboard is determining which squares from its current position represent valid moves. Code must be combined from last week’s lesson (setting the knight on the chessboard at a random spot) with the movement code presented a few lessons back.

Figure 1 shows the results desired, with the knight’s random position marked by the letter K and valid potential moves shown as asterisks.

knight on a chessboard showing moves

Figure 1. Potential moves for a knight on a chessboard.

To plot the knight’s moves I created the moveto() function. It accepts the knight’s current position (k) and an array of potential moves (m[]) as arguments. The knight’s position is randomly set in the main() function. The array of potential moves is also declared there, but its values are initialized in the moveto() function:

/* plot the knight moves
   k = position
   m[] = array to hold potential moves */
void moveto(int k, int m[])
{
    struct position {
        int row;
        int col;
    };
    /* offsets to move the knight */
    struct position pairs[KM] = {
        { -2,-1 }, { -2, 1 }, { -1, -2 }, { -1, 2 },
        { 1, -2 }, { 1, 2 }, { 2, -1 }, { 2, 1 }
    };
    int x,krow,kcol,r,c;

    /* calculate knight's row and column
       to make later calculations more
       readable */
    kcol = k % SIZE;
    krow = (k - kcol)/SIZE;
    /* plot the potential knight moves
       up to KM (8) of them */
    for( x=0; x<KM; x++ )
    {
        /* find new square position */
        r = krow + pairs[x].row;
        c = kcol + pairs[x].col;
        /* check for valid moves */
        if( (r<0 || r>=SIZE) || (c<0 || c>=SIZE) )
        {
            /* square is out of bounds */
            m[x] = -1;
        }
        else
        {
            /* plot position */
            m[x] = r * SIZE + c;
        }
    }
}

Literal KM equals the number of potential knight moves, set to eight. The moves are defined in the position structure pairs as row and column offsets. This topic was discussed in an earlier lesson.

The knight’s row (krow) and column (kcol) position is obtained from these expressions:

kcol = k % SIZE;
krow = (k - kcol)/SIZE;

This translation is necessary as the pairs[] array uses row and column offsets.

A for loop processes all potential moves, zero through KM. For each pairs[] value, a row (r) and column (c) is obtained:

r = krow + pairs[x].row;
c = kcol + pairs[x].col;

An if test confirms whether the row/column value is in range:

if( (r<0 || r>=SIZE) || (c<0 || c>=SIZE) )

If the row (r) or column (c) is out of range, -1 is set in the m[] array. Otherwise, the position is plotted and set in the array as a linear value:

m[x] = r * SIZE + c;

The array argument m[] need not be returned from the moveto() function. It’s one of those weird array/pointer things that works in C.

The main() function is updated to add the moveto() function call. Also the chess_board() function is updated to accept the moves[] array as a second argument. A for loop is added to the function to process the moves[] array, setting asterisks in those squares where the knight can move and ignoring the -1 values in the array.

The full code is available on GitHub. The output doesn’t yet match Figure 1 as the number of valid moves isn’t counted. Remember: One step at a time!

Once I got the first version of the code to work, I added another function, movecount(). This function processes the moves[] array, determining how many moves are valid. It tallies those elements not equal to -1.

/* count the valid moves
   m[] = array of move counts
   -1 value for no move */
int movecount(int m[])
{
    int x,count;

    count = 0;
    /* scan the array and tally values
       zero or greater (non -1) */
    for( x=0; x<KM; x++ )
    {
        if( m[x] >= 0 )
            count++;
    }

    return(count);
}

The updated code is available on GitHub.

The movecount() function isn’t just for reporting the output, as shown in Figure 1. No, it comes in handy as the code progresses. The goal is to determine which of the valid squares the knight can move to based on the number of next moves possible. This topic is tackled in next week’s Lesson.

Leave a Reply