#include "Tile.h"
#include "Board.h"

#include <cassert>
#include <string>
#include <iostream>
#include <fstream>

#include <qgrid.h>
#include <qpalette.h>
#include <qguardedptr.h>

using std::vector;
using std::iterator;
using std::string;
using std::cout;
using std::ifstream;

using namespace std;
//**********Couldn't get vector iterators to work w/o using std! sorry


bool IsWord(const string testme)
{
std::ifstream fcin;
assert (testme.empty() == false && testme.length() <= 15);
string test = testme;
for (int i = 0; i <test.length(); i++)
		{ // makes everything lowercase letters
		test[i] += ('a' - 'A'); }

string filename = "00.txt";
string tester;
bool isit = false;

filename[0] = testme[0] - ('A' -'a');  //Make testme[0] the letter on the first tile;
filename[1] =  (testme.length()) + ('1'- 1) ;
const char *f =(filename.data());
fcin.open(f);

if (fcin.fail())
	return false;

do
{	std::getline(fcin, tester);
			
	if (tester.length() == 0) continue;
	if (tester.length() > 1) {if (tester[1] > test[1]) return false;}
	if (test == tester) return true; 
	
}
while(!fcin.eof());
fcin.clear();
fcin.close();


return false;

}





//Color coded Bonus spaces!!!!!!!!!
const QColor LetterBonusColor[2] = {QColor(120,120,250), QColor(50,50,180)};
const QColor WordBonusColor[2] = {QColor(250, 120, 150), QColor(150, 50, 50)};
/////////////////////////////////////////////////////////////////////////////////



//********************************************************************************/
//	Board class method definitions
//********************************************************************************/
//********************************************************************************/



//-------------------------------------------------------------------------------
//	default constructor sets Boardspace values i.e. bonuses to proper value - NOT VERY PRETTY
//-------------------------------------------------------------------------------

Board::Board( QWidget* parent, const char* name)
	: QGrid(BOARD_SIZE, parent, name)
{ 	// yes it's really ugly but it works for now .... 
	// basically the idea is that i created two 2D c style arrays, one for letter bonuses one for word bonuses
	// then i set them all to 1
	// then i set the ones whose subscripts represent the coordinates of a space with a bonus to either 2 or 3
	// (since the board is very symmetric i 'mirrored' the values for each bonus space)
	// then i built the boardspace arrary with the values from the word and letter bonus arrays as the parameters of the boardspace constructor

	setCaption("Scrabble Board");
		//title bar caption

	setMinimumSize(350,350);
	setSpacing(2);
	setPalette( QPalette(QColor(250,250,200)) );
		//give it that classic pea yellow color


	//********************************************************************************/
	//********************************************************************************/
	// NOW, this bunch of crap is all just to intialize these two arrays
	// which hold the location of the letter and word bonuses
	int LetterBonus [BOARD_SIZE][BOARD_SIZE];
	int WordBonus [BOARD_SIZE][BOARD_SIZE];

	for (int c = 0; c <BOARD_SIZE; c++)
	{
		for (int c1 = 0; c1 <BOARD_SIZE; c1++)
		{
			LetterBonus [c][c1] = 1;
			WordBonus [c][c1] = 1;
		}
	}

	int a, b; 
	a = 5; b = 1; 
	LetterBonus[a][b] = LetterBonus[b][a] = LetterBonus[a][a] = 3;
	LetterBonus[BOARD_SIZE - 1 - a][b] = LetterBonus[BOARD_SIZE - 1 - b][a] = LetterBonus[BOARD_SIZE - 1 - a][a] = 3;
	LetterBonus[BOARD_SIZE - 1 -a][BOARD_SIZE - 1 -b] = LetterBonus[BOARD_SIZE - 1 -b][BOARD_SIZE - 1 -a] = LetterBonus[BOARD_SIZE - 1 -a][BOARD_SIZE - 1 -a] = 3;
	LetterBonus[a][BOARD_SIZE - 1 -b] = LetterBonus[b][BOARD_SIZE - 1 -a] = LetterBonus[a][BOARD_SIZE - 1 -a] = 3;
	
	a = 3; b = 0; 
	LetterBonus[a][b] = LetterBonus[b][a] = 2;
	LetterBonus[BOARD_SIZE - 1 - a][b] = LetterBonus[BOARD_SIZE - 1 - b][a] = 2;
	LetterBonus[BOARD_SIZE - 1 -a][BOARD_SIZE - 1 -b] = LetterBonus[BOARD_SIZE - 1 -b][BOARD_SIZE - 1 -a] = 2;
	LetterBonus[a][BOARD_SIZE - 1 -b] = LetterBonus[b][BOARD_SIZE - 1 -a] = 2;
	a = 6; b = 2; 
	LetterBonus[a][b] = LetterBonus[b][a] = 2;
	LetterBonus[BOARD_SIZE - 1 - a][b] = LetterBonus[BOARD_SIZE - 1 - b][a] = 2;
	LetterBonus[BOARD_SIZE - 1 -a][BOARD_SIZE - 1 -b] = LetterBonus[BOARD_SIZE - 1 -b][BOARD_SIZE - 1 -a] = 2;
	LetterBonus[a][BOARD_SIZE - 1 -b] = LetterBonus[b][BOARD_SIZE - 1 -a] = 2;
	LetterBonus[a][a] =  2;
	LetterBonus[BOARD_SIZE - 1 - a][a] = LetterBonus[a][BOARD_SIZE - 1 - a] = 2;
	LetterBonus[BOARD_SIZE - 1 -a][BOARD_SIZE - 1 - a] =  2;
	
	a = 7; b = 3; 
	LetterBonus[a][b] = LetterBonus[b][a] = 2;
	LetterBonus[BOARD_SIZE - 1 - a][b] = LetterBonus[BOARD_SIZE - 1 - b][a] = 2;
	LetterBonus[BOARD_SIZE - 1 -a][BOARD_SIZE - 1 -b] = LetterBonus[BOARD_SIZE - 1 -b][BOARD_SIZE - 1 -a] = 2;
	LetterBonus[a][BOARD_SIZE - 1 -b] = LetterBonus[b][BOARD_SIZE - 1 -a] = 2;

	for (a =1; a <5;a++)
	{
		WordBonus[a][a] =  2;
		WordBonus[BOARD_SIZE - 1 - a][a] = WordBonus[a][BOARD_SIZE - 1 - a] = 2;
		WordBonus[BOARD_SIZE - 1 -a][BOARD_SIZE - 1 - a] =  2;
	}

	WordBonus[7][7] = 2;
	
	WordBonus[0][0] = 3;
	WordBonus[14][0] = 3;
	WordBonus[0][14] = 3;
	WordBonus[14][14] = 3;
	WordBonus[0][7] = 3;
	WordBonus[14][7] = 3;
	WordBonus[7][0] = 3;
	WordBonus[7][14] = 3;

	//********************************************************************************/
	//********************************************************************************/

	//********************************************************************************/
	//this constructs the GameBoard vector, and sets all the boardspaces to their
	//proper bonus values and colors
	GameBoard.resize(BOARD_SIZE);

	//the x coordinate
	for (int j = 0; j<BOARD_SIZE ; j++)
	{
		// the y coordinate
		for (int i = 0; i <BOARD_SIZE ; i++)
		{
			GameBoard[i].resize(BOARD_SIZE);

			GameBoard[i][j] = new Boardspace(this, 0, WordBonus[i][j], LetterBonus[i][j] );
			if (LetterBonus[i][j] > 1)
				GameBoard[i][j]->setPalette( QPalette( LetterBonusColor[LetterBonus[i][j] -2]) );
			
			if (WordBonus[i][j] > 1)
				GameBoard[i][j]->setPalette( QPalette( WordBonusColor[WordBonus[i][j] -2]) );

			//connect individual boardspace clicks to Board's clicked function
			connect(GameBoard[i][j], SIGNAL(clicked()), SLOT(boardClicked()) );

			IsNew[j][i] = false;
		}

	}


	Register=0;
	CompTurn=false, LastPlayerSkipped=false, isFirstTurn=true;

	PlayerScore =0, ComputerScore=0;

}


//-------------------------------------------------------------------------------
//	deletes all dynamic memory
//-------------------------------------------------------------------------------
Board::~Board()
{

	for (int x=0 ; x < BOARD_SIZE ; x++)
	{
		for (int y=0 ; y < BOARD_SIZE ; y++)
			delete GameBoard[x][y];
	}

}


//-------------------------------------------------------------------------------
// adds a Tile to the board at location x,y from top left corner
//-------------------------------------------------------------------------------
void Board::addTile(Tile *NewTile, int x_position, int y_position)
{		

	assert ((x_position > 0) && (x_position <= BOARD_SIZE));
	assert ((y_position > 0) && (y_position <= BOARD_SIZE));

	assert (GameBoard[x_position-1][y_position-1] -> is_empty());

	GameBoard[x_position-1][y_position-1]->setTo( NewTile );

	IsNew[x_position-1][y_position-1] = true;
	
	vector<int> p;

	new_positions.push_back(p);
	new_positions.back().push_back(x_position-1);
	new_positions.back().push_back(y_position-1);


}

//-------------------------------------------------------------------------------
//	clears a Tile at position x,y
//-------------------------------------------------------------------------------
Board& Board::clearTile(int x_position, int y_position)
{

	assert (x_position > 0 && x_position <= BOARD_SIZE);
	assert (y_position > 0 && y_position <= BOARD_SIZE);

	GameBoard[x_position-1][y_position-1]->clear();
	IsNew[x_position-1][y_position-1] = false;

	for ( int i = 0; i < new_positions.size(); i++)
	{	
		if(new_positions[i][0] == (x_position-1)&&(new_positions[i][1] == (y_position-1)))
		{
			vector<vector<int> >::iterator the_itr;

			the_itr = new_positions.begin();
			new_positions.erase(the_itr+i);

			break;
		}
	}
	return *this;
}

//-------------------------------------------------------------------------------
//	erases entire board and reinitializes GameBoard
//-------------------------------------------------------------------------------
void Board::eraseBoard()
{ 

	//this is a little redundant, as it clears just the spaces in new_position
	//then clears new_position, then the loop below clears the entire board
	//but better than copying and pasting another for loop in her when not necessary
	resetTurn();

	for ( int i=0 ; i< (BOARD_SIZE*BOARD_SIZE) ; i++ )
		GameBoard[i%15][i/15]->clear();

	PlayerScore = ComputerScore = 0;
	emit humanScoreChanged(0);
	emit computerScoreChanged(0);

	CompTurn=false;
	isFirstTurn=true;
}

//-------------------------------------------------------------------------------
//	gets the Letter at spot x,y
//-------------------------------------------------------------------------------
char Board::getCharacter(int x_position, int y_position) const
{
	assert (x_position > 0 && x_position <= BOARD_SIZE);
	assert (y_position > 0 && y_position <= BOARD_SIZE);

	return GameBoard[x_position-1][y_position-1]->letter();
}

//-------------------------------------------------------------------------------
//	returns the letter bonus at a spot x,y
//-------------------------------------------------------------------------------
int Board::getLetterBonus(int x_position, int y_position) const
{
	assert (x_position > 0 && x_position <= BOARD_SIZE);
	assert (y_position > 0 && y_position <= BOARD_SIZE);

	return GameBoard[x_position-1][y_position-1]->letterBonus();
}

//-------------------------------------------------------------------------------
//	returns the letter ID of the boardspace at x,y
//-------------------------------------------------------------------------------
int Board::getLetterID(int x_position, int y_position) const
{
	assert (x_position > 0 && x_position <= BOARD_SIZE);
	assert (y_position > 0 && y_position <= BOARD_SIZE);

	return GameBoard[x_position-1][y_position-1]->letterID();
}

//-------------------------------------------------------------------------------
//	returns total value of a letter at boardspace x,y including letterbonus
//-------------------------------------------------------------------------------
int Board::getValue(int x_position, int y_position) const
{
	assert (x_position > 0 && x_position <= BOARD_SIZE);
	assert (y_position > 0 && y_position <= BOARD_SIZE);

	return GameBoard[x_position-1][y_position-1]->value();
}

//-------------------------------------------------------------------------------
//	returns word bonus multiplier at boardspace x,y
//-------------------------------------------------------------------------------
int Board::getWordBonus(int x_position, int y_position) const
{
	assert (x_position > 0 && x_position <= BOARD_SIZE);
	assert (y_position > 0 && y_position <= BOARD_SIZE);

	return GameBoard[x_position-1][y_position-1]->wordBonus();
}


int Board::getPlayerScore() const
{
	return PlayerScore;
}

int Board::getComputerScore() const
{
	return ComputerScore;
}


//********************************************************************************/
//	The Fun Stuff!!
//
//	This beaut does the logic at the end of a turn, scores the words, resets the
//	turn if necessary, plays the computer and scores it.  also checks for certain
//	end of game conditions, i.e. both players pass == game over
//-------------------------------------------------------------------------------
void Board::newTurn()
{	

	int score=-1;

	do {	

	if (!new_positions.empty())	//if player did not skip turn
	{	
		//letters have to be in a row
		if (!AreNewLettersOneWord() )
		{	
			emit resetHand();
			resetTurn();
			return;
		}

		score = FindAndScoreNewWords();

		//score less than 0 signals not a word
		//the other condition keeps 1 letter from being word at very beginning of game
		if (score < 0 || (score==0 && new_positions.size()==1) )
		{
			cout << "Not a word!! error code: " << score<< "\n";
			emit resetHand();
			resetTurn(); 
			return;
		}
		//add bonus for using all your tiles
		else if ( new_positions.size() == 7 || (CompTurn && new_positions.size()==7) )
			score += 50;

		// update scores/////////////////////////////////////
		if (CompTurn)
		{	
			ComputerScore += score;
			emit computerScoreChanged( ComputerScore ); 
			CompTurn = false;
		}
		else
		{
			PlayerScore += score;
			emit humanScoreChanged( PlayerScore ); 
			cout << score << " human score\n"; 
			CompTurn = true;
		}

		// reset new positions stuf///////////////
		new_positions.clear();
		for (int x=0 ; x < BOARD_SIZE ; x++)
		{
			for (int y=0 ; y < BOARD_SIZE ; y++)
				IsNew[x][y] = false;
		}
		//////////////////////////////////////////

		LastPlayerSkipped=false;
			//this player played, so didn't skip
		isFirstTurn=false;
			//if played then not first turn anymore



	}	//end of if player didn't skip

	else if (LastPlayerSkipped && !isFirstTurn) //if last player also skipped
	{
		emit gameOver();
		return;
	}
	
	else	//current player skipped, last did not
	{
		LastPlayerSkipped=true;
		CompTurn = !CompTurn;
			//now switch turns
	}

	//computer Plays its hand, is this the right placement??
	if (!isFirstTurn)
		ComputerPlayWord();
	}
	// do this whole loop until its not the computers turn anymore
	while (CompTurn);


	for (int i=ComputerHand.size()-1; i>=0; i--)
		cout << ComputerHand[i]->letter() << " ";
	cout << "\n";

}

//*************************************************************************
// clears board of new tiles and resets the new_positions vector
//*************************************************************************
void Board::resetTurn()
{
	if (!new_positions.size())
		return;

	for (int i=0 ; i<new_positions.size() ; i++)
	{
		GameBoard[ new_positions[i][0] ][ new_positions[i][1] ]->clear();
	}

	new_positions.clear();

	for (int y=0 ; y < BOARD_SIZE ; y++)
	{
		for (int x=0 ; x < BOARD_SIZE ; x++)
			IsNew[x][y] = false;
	}
}

//*************************************************************************
//	delete the Computer tiles in its hand
//*************************************************************************
void Board::deleteComputerHand()
{
	for (int i=ComputerHand.size()-1; i>=0; i--)
		delete ComputerHand[i];

	ComputerHand.clear();
}
		

//-------------------------------------------------------------------------------
// AreNewLettersOneWord
//-------------------------------------------------------------------------------
// tells if new letters form a single word.
// NOTE word being defined as in a single, unbroken line
// finds first and last tile position and sees if there are letters on tiles in between
// makes sure there are no other positions besides those
bool Board:: AreNewLettersOneWord() const
{
//		if (new_positions.empty()) {return true;} // if user decides to pass, or trade
	if (new_positions.size() == 1) {return true;} // if user only plays one letter, must be ok
		
	// ****************************find out if vertical or horizontal word****************************
	bool vertical, horizontal;
	vertical = horizontal = true;
	
	// if all the new positiosn don't have the same x coordinate, must not be vertical
	for (int i = 0; i <new_positions.size(); i++)
	{	if (new_positions[0][0] != new_positions[i][0])
		{	
			vertical = false; break;
		}
	}
	
	// if all the new positions don't have the same y coordinates, must not horizontal
	for (i = 0;  i <new_positions.size(); i++)
	{	if (new_positions[0][1] != new_positions[i][1])
		{	
			horizontal = false; break;
		}
	}

	// if neither vertical nor horizontal, not a single word
	if (!vertical && !horizontal) {	return false;}
					
	// ****************************finds first and last new letter****************************			
	
	// if vertical, the y coordinate changes, if horizontal, x changes
	int changing = vertical ? 1 : 0;
	int max, min;
	// sets min and max to the first as a starting point
	max = min = new_positions [0][changing];
	for (i = 1; i <new_positions.size(); i++)
	{	
		max = (new_positions [i][changing] > max) ? new_positions[i][changing] : max;
		min = (new_positions [i][changing] < min) ? new_positions[i][changing] : min;
	}
			
	// **************checks to see if there is a tile on each space between first and last new letter**************
	for (i = min +1; i < max; i++)
	{	if ((vertical) && ( GameBoard[(new_positions[0][0])  ][ i ] -> is_empty())) {return false;}
		if ((horizontal) && ( GameBoard[ i ][ (new_positions[0][1]) ] -> is_empty())) {return false;}
	}

// if it got this far must be ok		
return true;

}

//-------------------------------------------------------------------------------	
// Find and Score New Words
//-------------------------------------------------------------------------------
// returns score of new words
// return -1 if new words are not spelled correctly 
// return -2 if the word isn't touching anything else on board
//         (unless 7,7 (the start point) is one of the new letters, then returns score)
// assumes the AreNewLettersOneWord function returns true

int Board::FindAndScoreNewWords() const
{	
bool NewWordIsAttached = false;
vector <vector <int> > positions_of_words;	 
int score = 0;

for (int i = 0; i <new_positions.size();i++)
{ 
	string Hword; // horizontal word touching specific new tile
	vector <int> first_position; // a coordinate vector for the position of the first letter in the word
	vector <int> last_position; // a coordinate vector for the position of the second letter in the word
	
	int f = (new_positions[i][0] );
	int g = ( new_positions[i][1] );
	Hword.insert(0, (GameBoard [f ] [g] ->letter()));
	
	// **************search left and add those letter to the beginning of word**************

	int left = 0;
	
	for (;;)
	{	left++;
		// make sure not about to check over the edge of the board
		if (new_positions[i][1] - left < 0) 
			{first_position.push_back(new_positions[i][0]);
			first_position.push_back(0);
			break;}

		// break if space is empty
		if (GameBoard[ new_positions[i][0] ] [ new_positions[i][1] - left ] -> is_empty())
			{// the first one empty tells where the first letter of the word is 
			first_position.push_back(new_positions[i][0]);
			first_position.push_back( new_positions[i][1] - left +1);					
			break;}

		// if tile is old that means it is attached
		if (!(IsNew[ new_positions[i][0] ] [ new_positions[i][1] - left ])) 
			{NewWordIsAttached = true;}
		
		// insert the letter into the string
		string L = "0";
		L[0] = (GameBoard[ new_positions[i][0] ] [ new_positions[i][1] - left ] ->letter());
		Hword.insert(0,L);

	}
	

// **************look right and add those letters to the end**************
	int right = 0;
	for (;;)
	{	right++;
		// make sure not about to check over the edge of the board
		if (new_positions[i][1] + right > BOARD_SIZE-1) 
			{last_position.push_back(new_positions[i][0]);
			last_position.push_back(BOARD_SIZE-1);
			break;}
		
		if (GameBoard[ new_positions[i][0] ] [ new_positions[i][1] +right ] -> is_empty()) 
			{last_position.push_back(new_positions[i][0]);
			last_position.push_back(new_positions[i][1] +right -1);					
			break;}
		
		if (!(IsNew[ new_positions[i][0] ] [ new_positions[i][1] +right ])) // if tile is old that means it is attached
			{NewWordIsAttached = true;}

		string L = "O";
		L[0] =  GameBoard[ new_positions[i][0] ] [ new_positions[i][1] +right ] ->letter();
		Hword.insert(Hword.length() , L);

	}
	// ************** Spell Check and Score Word **************
if (Hword.length() != 1) // if length of the word is only one, don't have to spell check or have separate score
	{cout << Hword<<"is horizontal";
	// check to see if that word is already in list
	for (int w = 0; w<positions_of_words.size(); w +=2)
		{if (positions_of_words[w][0] == first_position[0] && positions_of_words[w][1] == first_position[1])
			{if (positions_of_words[w+1][0] == last_position[0] && positions_of_words[w+1][1] == last_position[1])
				{first_position.clear(); last_position.clear(); break;}}
		}
	// score and spell check word
	if (!first_position.empty())
		{// if not a word, return -1
		if (!IsWord(Hword)) return -1;
		
		score += ScoreWord(first_position, last_position);
		
		//add the positions of the word to the vector so it won't be checked and scored again
		positions_of_words.push_back(first_position);
		positions_of_words.push_back(last_position);}
	}	
	
	first_position.clear(); last_position.clear();

	string Vword;
	Vword.insert(0,GameBoard[ new_positions[i][0] ] [ new_positions[i][1]] ->letter());

	// ************** Look left for touching tiles and add them to beginning**************
		
	int up = 0;
	for (;;)
	{	up++;
		// make sure not about to check over the edge of the board
		if ( new_positions[i][0] - up<0) 
			{first_position.push_back(0);
			first_position.push_back(new_positions[i][1]);
			break;}
		
		if (GameBoard[new_positions[i][0] - up] [ new_positions[i][1] ] -> is_empty()) 
			{first_position.push_back(new_positions[i][0] - up + 1);
			first_position.push_back(new_positions[i][1]);					
			break;}
		
		string L = "0";
		L[0] = GameBoard[ new_positions[i][0] - up ] [ new_positions[i][1] ] ->letter();
		if (!(IsNew[ new_positions[i][0] - up ] [ new_positions[i][1] ])) // if tile is old that means it is attached
			{NewWordIsAttached = true;}
		Vword.insert(0,L);

	}
// ************** Look right for touching tiles and add them to end**************
	int down = 0;
	for (;;)
	{	down++;
		
		// make sure not about to check over the edge of the board
		if (  new_positions[i][0] + down > BOARD_SIZE-1) 
			{last_position.push_back(BOARD_SIZE-1);
			last_position.push_back(new_positions[i][1]);
			break;}
		
		if (GameBoard[ new_positions[i][0] + down] [ new_positions[i][1] ] -> is_empty()) 
			{last_position.push_back(new_positions[i][0] + down-1);
			last_position.push_back(new_positions[i][1]);					
			break;}
		string L = "0";
		L[0] = GameBoard[ new_positions[i][0] +  down ] [ new_positions[i][1] ] ->letter();
		if (!(IsNew[ new_positions[i][0] +  down ] [ new_positions[i][1] ])) // if tile is old that means it is attached
			{NewWordIsAttached = true;}

		Vword.insert(Vword.length(), L);
	}



if (Vword.length() != 1)
	{// check to see if that word is already in list
	cout << Vword<<"is vertical\n";
	for (int w = 0; w<positions_of_words.size(); w +=2)
		{if (positions_of_words[w][0] == first_position[0] && positions_of_words[w][1] == first_position[1])
			{if (positions_of_words[w+1][0] == last_position[0] && positions_of_words[w+1][1] == last_position[1])
				{first_position.clear(); last_position.clear(); break;}}
		}
	// score and spell check word
	if (!first_position.empty())
		{if (!IsWord(Vword)) return -1;
		score += ScoreWord(first_position, last_position);
		positions_of_words.push_back(first_position);
		positions_of_words.push_back(last_position);}
	}	
first_position.clear(); last_position.clear();
}
 
if ((NewWordIsAttached)||(IsNew[7][7]))
{cout <<"Score:"<<score<<'\n';
return score + ((new_positions.size() == 7)? 50 : 0) ;}
else 

{
	return -2;}
}

//-------------------------------------------------------------------------------
	// scores a word that goes from start position to end position
	//-------------------------------------------------------------------------------
	// PRECONDITION:  the start_position and the end position vector represent the beginning and end of a word
	// (they should be two dimensional vectors with values from 0 to BOARD_SIZE - 1;
	// assumes that none of the tiles between them are empty and that they form a horizontal or vertical word
int Board::ScoreWord(const vector <int> start_position, const vector<int> end_position) const
{	
	assert((start_position.size() == 2) && (end_position.size() == 2));
	cout <<"start position:"<<start_position[0]<<start_position[1];
	cout <<"end position:"<<end_position[0]<<end_position[1]<<'\n';
	int score = 0;
	int wordXbonus = 1;
	
	if (start_position[0] == end_position[0]) // then vertical word
	{
		for (int y = start_position[1]; y <= end_position[1]; y++)
		{	assert(!GameBoard[start_position[0]] [y] -> is_empty());
			if (IsNew[start_position[0]] [y])
			{	
				score += GameBoard[start_position[0]] [y] -> value();
				
				wordXbonus *= GameBoard[start_position[0]] [y] -> wordBonus();
			}
			else 
			{
				score += GameBoard[start_position[0]] [y] -> points();
			}
			
		}
		return score * wordXbonus;
	}

	// otherwise must be a horizontal word
	for (int x = start_position[0]; x <= end_position[0]; x++)
	{	
		assert(!GameBoard [x] [start_position[1]] -> is_empty());
		if (IsNew[x] [start_position[1]])
		{	
			score += GameBoard[x] [start_position[1]] -> value();
			wordXbonus *= GameBoard[x] [start_position[1]] -> wordBonus();
		}
			 else {score += GameBoard[x] [start_position[1]] -> points();}
	}
		
	return score * wordXbonus;

}


//*************************************************************************
//	this slot is called everytime a boardspace is clicked.  its main purpose
//	is to set the boardspace to the value the player wants
//*************************************************************************
void Board::boardClicked()
{
	//ignore stupid human when computer is thinking
	//and when the Register is empty(player hasn't selected a tile from hand)
	if (!Register || CompTurn)	
	{
		cout<< "ignoring board click cuz of user\n";
		return;}

	// all of this is just finding which tile was clicked/////////////////
	QGuardedPtr<Boardspace> ptr;
	const Boardspace* temp = (Boardspace*)sender();

	int xpos=1, ypos=1;
	for (int y=0; y<BOARD_SIZE ; y++)
	{
		for (int x=0; x<BOARD_SIZE ; x++)
		{
			ptr = GameBoard[x][y];
			if ( ptr == temp )
			{	xpos = x; ypos = y; 
				cout << xpos << " " << ypos << "\n"; break;}
		}
	}

	//////////////////////////////////////////////////////////////////

	//make a new pointer to the boardspace that was clicked
	Boardspace* b = GameBoard[xpos][ypos];
	
	//if its not empty, then leave now!
	if (!b->is_empty())
		return;

	emit boardClicked(xpos, ypos);

	
	vector<int> p;

	//add its position to new_positions
	new_positions.push_back(p);
	new_positions.back().push_back(xpos);
	new_positions.back().push_back(ypos);
	IsNew[xpos][ypos] = true;

	//set it to the value int the Register using boardspace setTo(int)
	b->setTo(Register->letterID());
	Register = 0;
		//reset the Register

	//signal the board has been changed
	emit boardChanged();
	emit boardChanged(xpos, ypos);

}

//*************************************************************************
// change the register pointer to whatever was passed to it
//*************************************************************************
void Board::setRegister(const Tile* pTile)
{
	Register = pTile;
}

//**************************************************************************************FindSimplePlaces******
void Board::FindSimplePlaces()  
		// finds the places where there is room to add a word across an old word
		// returns the places possible in vector of struct RecommendedTile	 

{	OpenSpots.clear(); 
	for (int x_start = 0; x_start <BOARD_SIZE; x_start++)
		{for (int y_start = 0; y_start <BOARD_SIZE; y_start++)
			{// if there is a tile on the space 
			if (!(GameBoard[y_start][x_start] -> is_empty()))
				{
					// can go down without worry about conflicting words if either the space above is empty or the board ends above
					// but at this point these are just used to indicate whether at the edge of the board
					bool NoConflictAbove =  (y_start == 0); 
					bool NoConflictBelow = (y_start == BOARD_SIZE - 1);
					bool NoConflictLeft = (x_start == 0);
					bool NoConflictRight = (x_start == BOARD_SIZE -1);
					
					
				// ******look for potential for vertical word******	
					// look below
					
				
					double bonusweight1 =0;
					double bonusweight2 = 0;
					for (int below = y_start+1; ((below < BOARD_SIZE) && (below - y_start)<= MAX_COMPHAND+1); below++)
						{if (GameBoard[below][x_start] -> is_empty())
							{
							if (!NoConflictRight) {if (!GameBoard[below][x_start+1] -> is_empty()) {break;}}
							if (!NoConflictLeft) {if (!GameBoard[below][x_start-1] -> is_empty()) {break;}}
							if (below+1 != BOARD_SIZE) {if (!GameBoard[below+1][x_start] -> is_empty()) {break;}}
							
							bonusweight1 += GameBoard[below][x_start] -> letterBonus() * (8+y_start-below)/7.00;
							bonusweight1 += GameBoard[below][x_start] -> wordBonus()*2 * (8+y_start-below)/7.00;
							}
						else break;}
					below--; // because don't want to count the space where the loop broke;
				
					// look above
					for (int above = y_start-1; ((above >= 0) && (y_start - above)<= MAX_COMPHAND+1); above--)
						{if (GameBoard[above][x_start] -> is_empty())
							{
							if (!NoConflictRight) {if (!GameBoard[above][x_start+1] -> is_empty()) {break;}}
							if (!NoConflictLeft) {if (!GameBoard[above][x_start-1] -> is_empty()) {break;}}
							if (above != 0) {if (!GameBoard[above-1][x_start] -> is_empty()) {break;}}
							bonusweight2 += GameBoard[above][x_start] -> letterBonus() *(8-y_start+above)/7.00;
							bonusweight2 += GameBoard[above][x_start] -> wordBonus()*2*(8-y_start+above)/7.00;
							}
						else {break;}}
					above++;

					// if there is space add to OpenSpots
					if (!NoConflictAbove) {NoConflictAbove = (GameBoard[y_start-1][x_start] -> is_empty());}
					if (!NoConflictBelow) {NoConflictBelow = (GameBoard[y_start+1][x_start] -> is_empty());}
					if (NoConflictAbove && NoConflictBelow)
						{RecommendedTile T;
						T.vertical = true;
						T.FreeSpaces = bonusweight1 + bonusweight2 + GameBoard[y_start][x_start] -> points();
						T.position[0] = x_start;
						T.position[1] = y_start;
						T.after = below - y_start;
						T.before = y_start - above;
						T.letter = GameBoard[y_start][x_start] -> letter();
						OpenSpots.push_back(T);
					cout <<"vertical Word Suggestion: "<<T.position[0]<<T.position[1]<<T.letter
							 << "  FreeSpaces : "<<T.FreeSpaces
							 << "  before : "<<T.before
							 << "  after : "<<T.after<<"\n";
						}


				// look for potential for horizontal word
				// look left
					
					 bonusweight1 = 0;
					 bonusweight2 =0;
					for (int left = x_start-1; ((left >= 0) && (x_start - left)<= MAX_COMPHAND+1); left--)
						{if (GameBoard[y_start][left] -> is_empty())
							{
							if (!NoConflictAbove) {if (!GameBoard[y_start-1][left] -> is_empty()) {break;}}
							if (!NoConflictBelow) {if (!GameBoard[y_start+1][left] -> is_empty()) {break;}}
							if (left != 0) {if (!GameBoard[y_start][left-1] -> is_empty()) {break;}}
							
							bonusweight1 += GameBoard[y_start][left] -> letterBonus() * (8-x_start+left)/7.00;
							bonusweight1 += GameBoard[y_start][left] -> wordBonus()*2 * (8-y_start+below)/7.00;
							}
						else break;}
					left++; // because don't want to count the space where the loop broke;
				
					// look right
					for (int right = x_start+1; ((right < BOARD_SIZE) && (right-x_start)<= MAX_COMPHAND+1); right++)
						{if (GameBoard[y_start][right] -> is_empty())
							{
							if (!NoConflictAbove) {if (!GameBoard[y_start-1][right] -> is_empty()) {break;}}
							if (!NoConflictBelow) {if (!GameBoard[y_start+1][right] -> is_empty()) {break;}}
							if (right+1 != BOARD_SIZE) {if (!GameBoard[y_start][right+1] -> is_empty()) {break;}}
							
							
							bonusweight2 += (GameBoard[y_start][right] -> letterBonus()) * (8-right+x_start)/7.00;
							bonusweight2 += GameBoard[y_start][right] -> wordBonus()*2 * (8-right+x_start)/7.00;
							}
						else break;}
					right--;

					// if there is space add to OpenSpots
					if (!NoConflictLeft) {NoConflictLeft = (GameBoard[y_start][x_start-1] -> is_empty());}
					if (!NoConflictRight) {NoConflictRight = (GameBoard[y_start][x_start+1] -> is_empty());}
					if (NoConflictLeft && NoConflictRight)
						{RecommendedTile T;
						T.vertical = false;

						T.FreeSpaces = bonusweight1 + bonusweight2 + GameBoard[y_start][x_start] -> points() ;
						T.position[0] = x_start;
						T.position[1] = y_start;
						T.after = right - x_start;
						T.before = x_start - left;
						T.letter = GameBoard[y_start][x_start] -> letter();
						OpenSpots.push_back(T);
						cout <<"Horizontal Word Suggestion: "<<T.position[0]<<T.position[1]<<T.letter
							 << "FreeSpaces : "<<T.FreeSpaces
							 << "before : "<<T.before
							 << "after : "<<T.after<<"\n";
						}
				
				}
			}}
}


//*****************************************************************************ComputerPlayWord******
// Precondition: hand in the Board has right number of tiles
void Board::ComputerPlayWord()
{
	if (!CompTurn //|| isFirstTurn)
		)
		return;
	

	FindSimplePlaces();// for suggested places to play
	
	// creates parallel arrays of words, start and end points 
	vector <string> words; 
	vector <vector <int> > start;
	vector <vector <int> > end;
	List_Words(words, start, end);
	cout<<"words.size() "<<words.size()<<'\n';
	if (!words.empty()) {	cout << words[0] << start[0][0]<<start[0][1] <<end[0][0]<<end[0][1]; }
	// decides on which word to play, by whichever gives it max points
	int max_score  = 0;
	string bestword;
	vector <int> beststart;
	vector <int> bestend;
	for (int i = 0; i <words.size(); i ++)
		{int possible_score = ScoreWord(start[i], end[i], words[i]);
		if  ( possible_score > max_score)
			{max_score = possible_score;
			beststart = start[i];
			bestend = end[i];
			bestword = words[i];}
		}
	cout <<"Max Score = "<<max_score;
	// play word or pass
	if 	(max_score != 0)
		{ bool vertical = (beststart[0] == bestend[0]);
		for (i = 0; i <bestword.size(); i++)
			{int x = beststart[0] + (vertical? 0: i);
			int y = beststart[1] + (vertical? i: 0);
			if (GameBoard[y][x] ->is_empty())
			{
				addTile( TakeComputerTile(bestword[i]) ,y+1 ,x+1 );
			}
			}
		cout <<"Computer Plays "<<bestword<<" from "<<beststart[0]<<','<<beststart[1]<<" to "<<bestend[0]<<','<<bestend[1]<<'\n';
		}
}
//**************************************************************************************List_Words******	
void Board::List_Words 	(vector <string> & words, vector <vector <int> > & start, vector<vector <int> > & end)

{	string hand = "0000000";
	for (int a = 0; a < ComputerHand.size(); a++)
		{ hand[a] = ComputerHand[a]->letter();}
	if (hand.length() > ComputerHand.size())
		{hand.resize (ComputerHand.size());}
	
	if (OpenSpots.empty()) { words.clear(); start.clear();end.clear(); return;}
	// use position with highest weighted freespace first
	
	sort_positions();

	for (int p = 0; p<OpenSpots.size(); p++)
		{	
			// finds all words in the dictionary
			FindComputerWords(OpenSpots[p], hand, words, start, end);			
					
			if (!words.empty()) {return;}
		}

}	

//**************************************************************************************Copy******
// for simplification of the sort_positions function
 void Board::copy(RecommendedTile & left, RecommendedTile copy)
{	left.letter = copy.letter;
	left.after= copy.after;
	left.before = copy.before;
	left.FreeSpaces = copy.FreeSpaces;
	left.position[0] = copy.position[0];
	left.position[1] = copy.position[1];
	left.vertical = copy.vertical;
}

//***********************************************************************************sort_positions******
// bubble sort OpenSpots by FreeSpace
void Board::sort_positions()
{	
	RecommendedTile temp;
	for (int i = 0; i <OpenSpots.size(); i ++)
		{for (int j = 0; j <OpenSpots.size()-1; j++)
			{ 	
				if (OpenSpots[j].FreeSpaces < OpenSpots[j+1].FreeSpaces)
					{copy(temp, OpenSpots[j]);
					copy (OpenSpots[j], OpenSpots[j+1]);
					copy (OpenSpots[j+1], temp);
				}
			}
		}
}

//***********************************************************************************ScoreWord******		
//----------------------------------------------------------------------------------
// scores a word that will go from start position to end position with given letters
//----------------------------------------------------------------------------------
int Board::ScoreWord(const vector <int> start_position, const vector<int> end_position, const string letters) const
{	
	assert((start_position.size() == 2) && (end_position.size() == 2));
	
	// convert string of letters to array of letter values
	vector <int> letterpoints (letters.length());
	for (int i = 0; i <letters.length(); i ++)
	{	
		letterpoints[i] = LetterIDValue[static_cast<int>(letters[i]) - 65];
	}


	int score = 0;
	int wordXbonus = 1;
	
	if (start_position[0] == end_position[0]) // then vertical word
	{
		for (int y = start_position[1]; y <= end_position[1]; y++)
		{	
			if (GameBoard[start_position[0]] [y] -> is_empty())
			{	
				score += (GameBoard[start_position[0]] [y] -> letterBonus())*letterpoints[ end_position[1] - y];
				
				wordXbonus *= GameBoard[start_position[0]] [y] -> wordBonus();
			}
			else 
			{
				score += GameBoard[start_position[0]] [y] -> points();
			}
			
		}
		return score * wordXbonus+ ((letters.length() == 7) ? 50 : 0);
	}

	// otherwise must be a horizontal word
	for (int x = start_position[0]; x <= end_position[0]; x++)
	{	
		
		if (GameBoard [x] [start_position[1]] -> is_empty())
		{	
			score += (GameBoard[x] [start_position[1]] -> letterBonus())*letterpoints[x - start_position[0] ];
			wordXbonus *= GameBoard[x] [start_position[1]] -> wordBonus();
		}
			 else {score += GameBoard[x] [start_position[1]] -> points();}
	}
	
	 

	return score * wordXbonus + ((letters.length() == 7) ? 50 : 0); // if use all 7 letters 50 pt bonus
}

		
Tile* Board::TakeComputerTile(char tileLetter)
{
	for (int i = 0; i < (ComputerHand.size()); i++)
 	
	{	if (ComputerHand[i]->letter() == tileLetter)
		{Tile** t;
		t = &ComputerHand[i];  
		ComputerHand.erase(t);
			return (new Tile (tileLetter)); 
		}
	}
		
 return 0;
}

void Board::FindComputerWords(RecommendedTile Recommend, string hand, vector <string> & words, vector <vector <int> > &start, vector <vector <int> >&end)
{
	for (int TotalLetters = ComputerHand.size(); TotalLetters > 1; TotalLetters--) // change to const
		{
		int lettersafter = TotalLetters - min (ComputerHand.size(), Recommend.before);	
		for (int lettersbefore = min (ComputerHand.size(), Recommend.before); lettersafter < Recommend.after; lettersbefore --)
				{vector <string> c = make_words(lettersbefore, lettersafter, Recommend.letter, hand);
				
				for (int i = 0; i < c.size(); i ++)
					{cout <<c[i];
					cout <<"start: ";
					words.push_back(c[i]);
					vector <int> s, e;
					s.push_back(Recommend.position[0]);
					s.push_back(Recommend.position[1]);
					e.push_back(Recommend.position[0]);
					e.push_back(Recommend.position[1]);
					if (Recommend.vertical)
						{s[1] -= lettersbefore;
						e[1] +=lettersafter;}
					else
						{s[0] -= lettersbefore;
						e[0] +=lettersafter;}
					cout <<s[0]<<s[1];
					start.push_back(s);
					end.push_back(e);}
				
				lettersafter++;}
			if (!words.empty()) {return;}
		}
}

vector<string> Board::make_words(int letters_before, int letters_after, char orginal_letter, string hand)const
{
	// make strings ...  have to be words
	// make strings ...  have to be words
	assert (!((letters_before <= 0) && (letters_after <=0)));
	if (letters_after <0){letters_after =0;}
	if (letters_before <0){letters_before =0;}
	// assert (orginal_letter is a capital letter);
	vector <string> words;
	int PossibleCombos = 1;
	for (int L = hand.length(); L >hand.length()-letters_before-letters_after; L--) 
	{PossibleCombos *= L;} 
// adjust possible combos if want the computer to be dumber 

for (int shuffle_hand = 1; shuffle_hand <= PossibleCombos; shuffle_hand++)	
{
	string word;
			word.resize( letters_before + letters_after + 1);
			for (int before = 0; before <letters_before; before++)
				{word[before] = hand[before];}
			word[letters_before] = orginal_letter;
			for (int after = 1; after <=letters_after; after++)
				{word [letters_before + after] = hand [letters_before+after-1];}
			assert (word.length() == (letters_before + letters_after +1));
			
			if (IsWord(word)) 
				{words.push_back(word);
				//cout<<word<<"!!!\n\n";
			}
			//else {cout <<"-";}
	char temp = '0';	int i = 7;
				
	for (int factorial = 5040; factorial > 24; factorial = factorial/i )
	{
		if (shuffle_hand % (factorial) == 0)
		{	temp = hand[0];
			hand[0] = hand [i];
			hand[i] = temp;
			break;}
		i--;
	}
	if (shuffle_hand % 24 == 18)
		{temp = hand [0];
		hand[0] = hand [3];
		hand [3] = temp;}
	if ((shuffle_hand % 6 == 0) && (temp == '0'))
		{temp = hand[1];
		hand[1] = hand[3];
		hand[3] = temp;}
	if ((temp == '0') && (shuffle_hand % 2))
		{temp = hand[2];
		hand[2] = hand[1];
		hand[1] = temp;}
	if (temp == '0')
		{temp = hand[0];
		hand[0] = hand [2];
		hand[2]= temp;}

}

	return words;
}

//*************************************************************************
//	get a tile and put it in the computers hand
//*************************************************************************
void Board::getComputerTile(int letterID)
{
	ComputerHand.push_back( new Tile(letterID));
}

//*************************************************************************
//	return the no of tiles in the comp's hand
//*************************************************************************
int Board::CompTilesInHand() const
{
	return ComputerHand.size();
}


//*************************************************************************
//	return the total value of the tiles int the comp's hand
//*************************************************************************
int Board::computerHandValue() const
{
	int handValue=0;
	for (int i=ComputerHand.size()-1; i>=0; i--)
		handValue+=ComputerHand[i]->value();

	return handValue;
}

//*************************************************************************
//	used to change fontsize to fit boardspace size
//*************************************************************************
void Board::resizeEvent(QResizeEvent*e)
{
	int width = e->size().width();
	int height = e->size().height();

	for (int i=0; i<BOARD_SIZE*BOARD_SIZE; i++)
		GameBoard[i%15][i/15]->resize(width/15-2, height/15-2);
}

//*************************************************************************
//	size policy information
//	means that board expands both ways to fill up all the space given to it
//*************************************************************************
QSizePolicy Board::sizePolicy() const
{
	return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}


//*************************************************************************
// min function
//*************************************************************************
int min (int a, int b)
{return ((a<b)? a:b);}


