Computer Science 301 - Translators


Tutorial 1 - Backtracking algorithms and the N Queens problem - Solutions

The 4 Queens problem - place 4 Queens on a 4 x 4 chessboard so that none of them is threatened by any other.

  No problem in       Cannot place 2nd    Cannot place 2nd    Can place 2nd
  placing 1st Queen   Queen in top row    Queen in 2nd row    Queen in 3rd row

    1   2   3   4       1   2   3   4       1   2   3   4       1   2   3   4
  ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗
1 ║ Q │   │   │   ║   ║ Q │ X │   │   ║   ║ Q │   │   │   ║   ║ Q │   │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
2 ║   │   │   │   ║   ║   │   │   │   ║   ║   │ X │   │   ║   ║   │   │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
3 ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║   ║   │ Q │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
4 ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║
  ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝

So now we can try to place the third Queen in the third column:

  Cannot place 3rd    Cannot place 3rd    Cannot place 3rd    Cannot place 3rd
  Queen in top row    Queen in 2nd row    Queen in 3rd row    Queen in 4th row

    1   2   3   4       1   2   3   4       1   2   3   4       1   2   3   4
  ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗
1 ║ Q │   │ X │   ║   ║ Q │   │   │   ║   ║ Q │   │   │   ║   ║ Q │   │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
2 ║   │   │   │   ║   ║   │   │ X │   ║   ║   │   │   │   ║   ║   │   │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
3 ║   │ Q │   │   ║   ║   │ Q │   │   ║   ║   │ Q │ X │   ║   ║   │ Q │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
4 ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │ X │   ║
  ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝

Oh dear! Are we stuck completely? No, we can still back track and try to find another position for the 2nd Queen. We have already looked at rows 1 and 2 (no use) and row 3 (was okay until now!). That leaves row 4.

  The 2nd Queen can   Cannot place 3rd    Can place 3rd       Cannot place 4th
  also fit in row 4.  Queen in 1st row    Queen in 2nd row    Queen in any row

    1   2   3   4       1   2   3   4       1   2   3   4       1   2   3   4
  ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗
1 ║ Q │   │   │   ║   ║ Q │   │ X │   ║   ║ Q │   │   │   ║   ║ Q │   │   │ - ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
2 ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │ Q │   ║   ║   │   │ Q │ - ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
3 ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │ - ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
4 ║   │ Q │   │   ║   ║   │ Q │   │   ║   ║   │ Q │   │   ║   ║   │ Q │   │ - ║
  ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝

Oh dear! The 4th Queen cannot fit on any row in the 4th column. Are we at last stuck completely? Can we still back track and try to find another position for the 2nd Queen. No, there are no more. We shall have to backtrack still further and take the 2nd Queen right off, and also move the first Queen.

  The first Queen     Cannot place 2nd    Cannot place 2nd     Cannot place 2nd
  can go in row 2     Queen in row 1      Queen in row 2       Queen in row 3

    1   2   3   4       1   2   3   4       1   2   3   4       1   2   3   4
  ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗
1 ║   │   │   │   ║   ║   │ X │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
2 ║ Q │   │   │   ║   ║ Q │   │   │   ║   ║ Q │ X │   │   ║   ║ Q │   │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
3 ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║   ║   │ X │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
4 ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║
  ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝

This is getting frustrating. But if at first you don't succeed:

  Can place 2nd       Can place 3rd       Cannot place 4th    Cannot place 4th
  Queen in row 4      Queen in row 1      Queen in 1 or 2     Queen in row 3

    1   2   3   4       1   2   3   4       1   2   3   4       1   2   3   4
  ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗   ╔═══╤═══╤═══╤═══╗
1 ║   │   │   │   ║   ║   │   │ Q │   ║   ║   │   │ Q │ X ║   ║   │   │ Q │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
2 ║ Q │   │   │   ║   ║ Q │   │   │   ║   ║ Q │   │   │ X ║   ║ Q │   │   │   ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
3 ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │   ║   ║   │   │   │ Q ║
  ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢   ╟───┼───┼───┼───╢
4 ║   │ Q │   │   ║   ║   │ Q │   │   ║   ║   │ Q │   │   ║   ║   │ Q │   │   ║
  ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝   ╚═══╧═══╧═══╧═══╝

All things come to those who wait. Are there any other solutions do you suppose? How do you find them if there are? Could we do the same sort of thing for any number of Queens?

A good discussion of back-tracking algorithms is to be found in a classic text by Niklaus Wirth (inventor of Pascal, Modula, Modula-2 and Oberon, and one of the greatest computer scientist of our age). The book has the unusual name Algorithms + Data Structures = Programs, and is well worth consulting. It was published by Prentice Hall in 1976 in a Pascal edition, and again in 1985 in a Modula-2 edition.

Wirth gives a general pattern for finding solutions to these sorts of problems as follows (I have translated his notation slightly).

      PROCEDURE TryNextStep (VAR Successful : BOOLEAN);
        BEGIN
          InitializeDataStructures;
          REPEAT
            SelectPossibility;
            IF Acceptable THEN
              RecordPossibility;
              IF SolutionIncomplete THEN
                TryNextStep(Successful)
                IF NOT Successful THEN
                  CancelPossibility
                END
              END
            END
          UNTIL Successful OR NoMorePossibilities
        END TryNextStep;

Sometimes - as in the case of the Queens problem - one can parameterize this routine further, to include a counter I among the N items to be selected, and sometimes the NoMorePossibilities failure is easily determined in terms of a counter J that reaches a limit. Hence we get variations on this theme like:

      PROCEDURE TryNextStep (I, N : INTEGER; VAR Successful : BOOLEAN);
        VAR
          J : INTEGER;
        BEGIN
          InitializeDataStructures; J := 0;
          REPEAT
            INC(J); SelectPossibility(J);
            IF Acceptable THEN
              RecordPossibility;
              IF I < N THEN
                TryNextStep(I + 1, N, Successful)
                IF NOT Successful THEN
                  CancelPossibility(J)
                END
              END
            END
          UNTIL Successful OR (J = N) (* NoMorePossibilities for J *)
        END TryNextStep;

And here, finally, is essentially how Wirth develops this system for the specific case of finding a solution to the 8 Queens problem. This solution is given in Pascal (you should all be exposed to Pascal at some stage, even if the world shouts Java and C++ all day). Wirth is a fascinating programmer. He write very tight code - but is it always easy to follow? If not, why not?

   PROGRAM Queens;
   (* Find a solution to the 8 Queens problem - how do we place 8 Queens on
      a chessboard so that none of them is threatened by any other one.
      Code closely based on that by Niklaus Wirth in "Algorithms + Data
      Structures = Programs" (Prentice-Hall, 1976; page 145)
      Modifications by Pat Terry, Rhodes University, 2000 *)
     CONST
       Size = 8;
     VAR
       A : ARRAY [1 .. Size] OF BOOLEAN;
       B : ARRAY [2 .. 2*Size] OF BOOLEAN;
       C : ARRAY [-Size+1 .. Size-1] OF BOOLEAN;
       X : ARRAY [1 .. Size] OF INTEGER;
       I : INTEGER;
       Success : BOOLEAN;

     PROCEDURE Try (I : INTEGER; VAR Success : BOOLEAN);
       VAR
         J : INTEGER;
       BEGIN
         J := 1; Success := FALSE;
         WHILE NOT SUCCESS AND (J <= Size) DO BEGIN
           IF A[J] AND B[I+J] AND C[I-J] THEN BEGIN
             X[I] := J;
             A[J] := FALSE; B[I+J] := FALSE; C[I-J] := FALSE;
             IF I < Size
               THEN BEGIN
                 Try(I+1, Success);
                 IF NOT Success THEN BEGIN
                   A[J] := TRUE; B[I+J] := TRUE; C[I-J] := TRUE
                 END;
               END
               ELSE Success := TRUE;
           END;
           J := J + 1;
         END
       END;

     BEGIN
       FOR I := 1 TO 8  DO A[I] := TRUE;
       FOR I := 2 TO 16 DO B[I] := TRUE;
       FOR I := -7 TO 7 DO C[I] := TRUE;
       Try(1, Success);
       IF Success
         THEN FOR I := 1 TO Size DO Write(X[I]:4)
         ELSE Write('No solution');
       WriteLn;
     END.


Home  © P.D. Terry