
//  Program:  word_search
//  Author:   Chuck Stewart
//
//  Purpose:  A program to solve the word search problem where the
//     letters in the word do not need to appear along a straight
//     line.  Instead, they can twist and turn.  The only requirements
//     are two-fold:  the consecutive letters must be "8-connected" to
//     each other (meaning that the locations must touch along an edge
//     or at a corner), and no location may be used more than once.
//
//     The real issue is how to search for the letters and then record
//     locations as we search.  This is most easily done with a
//     recursive function.  This function will be written during
//     lecture. 
//
//     The input is from an input file.  The grid is a series of
//     strings, ended by a string that begins with '-'.  Each
//     subsequent string in the file is used to search the input.

#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

//  Simple class to record the grid location.  

class loc {
public:
  loc( int r=0, int c=0 ) : row(r), col(c) {}
  int row, col;
};

bool operator== ( const loc& lhs, const loc& rhs )
{  return lhs.row == rhs.row && lhs.col == rhs.col; }


//  Prototype for the main search function

bool search_from_loc( loc position, 
                      const vector< string >& board,
                      const string& word,
                      vector<loc>& path );


int
main( int argc, char* argv[] )
{
  if ( argc != 2 )
    {
      cerr << "Usage: " << argv[0] << " grid-file\n";
      return 1;
    }
  ifstream istr( argv[1] );
  if ( !istr )
    {
      cerr << "Couldn't open " << argv[1] << '\n';
      return 1;
    }

  vector< string > board;   
  string word;
  vector<loc> path;           //  The sequence of locations...
  string line;

  //  Input of grid from a file.  Stops when character '-' is reached.

  while ( (istr  >> line) && line[0] != '-' )
    board.push_back( line );

  
  while ( istr >> word )
    {
      bool found = false;
      vector< loc > path;  //  Path of locations in finding the word

      //  Check all grid locations.  For any that have the first
      //  letter of the word, call the function search_from_loc
      //  to check if the rest of the word is there.

      for ( unsigned int r=0; r<board.size() && !found; ++r )
        for ( unsigned int c=0; c<board[r].size() && !found; ++c )
          {
            if ( board[r][c] == word[0] && 
                 search_from_loc( loc(r,c), board, word, path ) )
              found = true;
          }

      //  Output results

      cout << "\n** " << word << " ** ";
      if ( found )
        {
          cout << "was found.  The path is \n";
          for( unsigned int i=0; i<path.size(); ++i )
            cout << "  " << word[i] << ":  (" << path[i].row
                 << "," << path[i].col << ")\n";
        }
      else
        {
          cout << " was not found\n";
        }
    }
  return 0;
}

bool on_path( loc position, vector<loc> const& path )
{
  for ( unsigned int i=0; i<path.size(); ++i )
    if ( position == path[i] ) return true;
  return false;
}


bool
search_from_loc( loc position, //  current position
                 const vector< string >& board,  
                 const string& word,  
                 vector<loc>& path )  //  path up to the current pos           
{
  path.push_back( position );
  if ( path.size() == word.size() ) // found whole word
    return true;
  int next_index = path.size();
  for ( int r=position.row-1; r<=position.row+1; ++r )
    for ( int c=position.col-1; c<=position.col+1; ++c )
      {
	if ( (r != position.row || c != position.col)  // skip ctr
	     && (r>=0 && r<=board.size()-1 && c>=0 && 
		 c<=board[r].size()-1)   //  check boundaries
	     && board[r][c] == word[next_index]  // found letter
	     && !on_path( loc(r,c), path )  // not on path
	     && search_from_loc( loc(r,c), board, word, path ) )
	  return true;  //  recursion worked
      } 
  path.pop_back();
  return false;
}


