2
\$\begingroup\$

Another one for some late night snack. - Knight's tour! Please provide your suggestions/flaws/optimization to this knight's tour backtracking code..

package com.komal.backtracking;

import java.util.concurrent.TimeUnit;

public class KnightsTour {
    static int size = 6;
    static int[][] chessBoard = new int[size][size];
    static int move;
    static int noOfBacktrackCalls;

    public boolean tourBackTrackRoutine(int row, int col) {
        boolean flag = false;
        noOfBacktrackCalls++;
        if (!isMoveSafe(row, col)) {
            return false;
        }
        move++;
        chessBoard[row][col] = move;

        if (move == size * size) {
            return true;
        }

        flag = true;


        int counter = 0;

        for (int i[] : possibleMoves) {
            counter++;
            int newX = row + i[0];
            int newY = col + i[1];
            if (flag = tourBackTrackRoutine(newX, newY)) {
                return true;
            } else {
                if (counter == possibleMoves.length) {
                    move--;
                    chessBoard[row][col] = 0;
                    return flag;
                } else {
                    continue;
                }
            }
        }
        return flag;

    }

    public boolean isMoveSafe(int row, int col) {

        if (row < 0 || col < 0 || !(row < size) || !(col < size)) {
            return false;
        }

        if (row == size || col == size) {
            return false;
        }
        if (chessBoard[row][col] > 0) {
            return false;
        } else {
            return true;
        }
    }

    int[][] possibleMoves = { { 2, 1 }, { 2, -1 }, { -2, 1 }, { -2, -1 }, { 1, 2 }, { 1, -2 }, { -1, 2 }, { -1, -2 } };

    public static void main(String[] args) {
        System.out.println("Solving...");
        long startTime = System.nanoTime();
        if (new KnightsTour().tourBackTrackRoutine(0, 0)) {
            System.out.println("Solved!!");
        } else {
            System.out.println("Cannot be solved!!");
        }
        long timeTaken = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
        System.out.println("\nCompleted in :" + timeTaken + " milli sec");
        System.out.println("\nTook " + noOfBacktrackCalls + " backtrack calls for completion!");
        for (int[] i : chessBoard) {
            System.out.print("\n{");
            for (int i1 : i) {
                System.out.print(i1 + ",\t");
            }
            System.out.print("}");
        }
    }

}

Output:

Solving...
Solved!!

Completed in :382 milli sec

Took 20092518 backtrack calls for completion!

{1, 12, 21, 28, 7,  10, }
{22,29, 8,  11, 20, 27, }
{13,2,  23, 4,  9,  6,  }
{30,35, 32, 17, 26, 19, }
{33,14, 3,  24, 5,  16, }
{36,31, 34, 15, 18, 25, }
\$\endgroup\$
1
  • \$\begingroup\$ 8x8 takes for ever to complete though! Waited for like 15 mins, no luck! \$\endgroup\$ Commented Jun 6, 2016 at 21:26

1 Answer 1

5
\$\begingroup\$
    static int size = 6;

This should be final, as you don't change it.

        boolean flag = false;
        noOfBacktrackCalls++;
        if (!isMoveSafe(row, col)) {
            return false;
        }
        move++;
        chessBoard[row][col] = move;

        if (move == size * size) {
            return true;
        }

        flag = true;

You initialize flag and then set it to something else without ever using it. Why bother? You could just say

        noOfBacktrackCalls++;
        if (!isMoveSafe(row, col)) {
            return false;
        }
        move++;
        chessBoard[row][col] = move;

        if (move == size * size) {
            return true;
        }

        boolean solved = true;

I renamed it to solved after I figured out what it was. The name flag didn't help me much with understanding what it did.

And the truth is that you don't need it. I'd simplify down to

        noOfBacktrackCalls++;
        move++;
        chessBoard[row][col] = move;

        if (move == size * size) {
            return true;
        }

Note that other code will have to change to make this work.

        int counter = 0;

        for (int i[] : possibleMoves) {
            counter++;
            int newX = row + i[0];
            int newY = col + i[1];
            if (flag = tourBackTrackRoutine(newX, newY)) {
                return true;
            } else {
                if (counter == possibleMoves.length) {
                    move--;
                    chessBoard[row][col] = 0;
                    return flag;
                } else {
                    continue;
                }
            }
        }
        return flag;

First, that continue doesn't do anything. You're already at the end of the loop. You can just let it finish. And without the continue, you don't need the else block.

As I said earlier, you don't actually need flag. You never set it to true except initially. The first time that you return flag, it will always be false. You just set it to false before the else block. Otherwise the else wouldn't run. The second return will only be reached if there are no possible moves or if flag is false. If you set flag to true in the loop, you always return immediately. And you know that possibleMoves is not empty, as you set it.

I'd write this block

        for (int i[] : possibleMoves) {
            int newX = row + i[0];
            int newY = col + i[1];
            if (isMoveSafe(newX, newY) && tourBackTrackRoutine(newX, newY)) {
                return true;
            }
        }

        move--;
        chessBoard[row][col] = 0;

        return false;

No flag needed.

I also removed counter. You were only using it to give a different behavior on the last iteration of the loop. But putting the code outside the loop accomplishes the same thing.

I moved the isMoveSafe to here so that it runs before the recursive call.

Performance

The performance is determined by the algorithm here. These changes tweak performance a bit, but the algorithm is still the problem. You may want to check out some previous questions for more ideas. E.g.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.