!written on aug 26, 2000 by siva@cse.iitb.ernet.in
Program KnightWalk
Implicit none
Logical, Dimension(8,8) :: Board 
Integer :: Row = 0, Col = 0, RowNext = 0, ColNext=0
Integer :: WalkLength = 0
Integer :: GetNum  ! same function we used last time. why declared?
                   ! not an INTERNAL function this time!
!initialize all squares to .false. since none has been visited
Board = .false.  ! this is ok. all squares have same value. loop not needed
! get start row and col from user
Row = Getnum(1,8,'Enter Start Row: ')
Col = Getnum(1,8,'Enter Start Col: ')

! if you forget the following, you may revisit this square.
Board(Row,Col) = .true. ! we have visited this square already.

Do
 Call NextMove(Board, Row, Col, RowNext, ColNext)
     ! subroutine does all of the following-
     !   computes next move (RowNext and ColNext)
     !          and marks it on the board Board(RowNext,ColNext)
     !   if no next move is possible sets RowNext to 0
 If (RowNext == 0) Exit  ! rowNext is 0 only when we reach a dead end
 Write (*,*) 'Move from: <', Row, ',', Col, '> to  <',    &
                         RowNext, ',', ColNext, '>'
 Row = RowNext ! this is next position
 Col = ColNext
 WalkLength = WalkLength + 1
End Do

Write (*,*)  'Walk ended after ', WalkLength, ' steps. Bye.'
End Program KnightWalk


  Integer Function Getnum(low, high, msg)
    Implicit none
    Integer, Intent(in) :: low, high
     ! note below that Len = * is ok since msg is input.
    Character(Len=*), Intent(in) :: msg
    Integer :: ans

    Do
       Write (*,*) msg, '(Between ', low, ' and ', high, ')'
       Read (*,*) ans
       If ((low <= ans) .and. (ans <= high)) Exit
       Write (*,*) 'You did not type a valid input. Please try again.'
    End Do
   Getnum = ans
  End Function Getnum

 Subroutine NextMove(Board, X, Y, X1, Y1)
 Implicit None
 ! example of more than one attribute for a variable
 ! remember: logical is type, intent and dimension are attributes.
 Logical, Intent(Inout), Dimension(8,8) :: Board
 Integer, Intent(In) :: X, Y
 Integer, Intent(Out) :: X1, Y1
 ! these two are local variables
 Integer :: Hor, Ver
 Logical :: MoveFound
 ! Is the logic of finding the next move is "complex"?
 ! no, only the representation (data structure + control structure)
 !        can be confusing unless we are systematic.
 ! -2, -1, 1, 2 are valid strides in either axis, but not 0
 ! so we need a DO loop where for counter = 0 we simply CYCLE (i.e. ignore)
 ! but neither horizontal nor vertical stride must take us off the board
 !  so check 1 <= new-pos <= 8 for both axis
 ! but if hor stride  is 1, then vertical MUST be 2 and vice versa
 ! so we need to check that abs(horizontal-stride) /= abs(vertical-stride)
 ! the above "tricks" make the code compact. 
 ! otherwise, we have to "enumerate" (brute-force) the 8 moves.
 MoveFound = .false.
 Do Hor = -2, 2   ! hor takes 5 values, but 0 is not ok.
   If ((Hor == 0) .or. ((X+Hor) < 1) .or. ((X+Hor) > 8)) Cycle
   Do Ver = -2, 2  ! ver takes 5 values, but 0 is not ok.
      ! also hor and ver cannot both be 1 (or both 2) for knight move
    If ((Ver == 0) .or. (abs(Hor) == abs(Ver)) .or.           &
              ((Y+Ver) < 1) .or. ((Y+ver) > 8)) Cycle
    If (.NOT. Board(X+Hor, Y+Ver)) MoveFound = .true.
    If (MoveFound) EXIT  ! we have found a free square
   End Do
   If (MoveFound) Exit  ! we have found a free square. 
 End Do
 If (MoveFound) Then   
   X1 = X + Hor       ! exited loop normally or after finding a move.
   Y1 = Y + Ver
   Board(X1,Y1) = .true.
 Else   ! we will reach here only if we cant find a move
   X1 = 0
   Y1 = 0
 End If
 End Subroutine NextMove


