//Name: David Yang, Sean McMillan, Dominic Golab
//File: Board.cpp
//For: CSE 30331: Scrabble Gmae
//12/6/09
/*Description: This file contains the functionality of the board class.
The board class holds a matrix of letters that represents the board and a matrix of ints that represents the boards multipliers. It has a Bag, banks, a dictionary and matrix objects. It combines them to make the base of the scrabble program.*/
#include "Board.h"
#include <iostream>
#include <string>
#include <ctype.h>

using namespace std;

//constructor: intantiates teh bag, and boards
Board::Board() :letterBag(), pointsBoard(15,15,1),letterBoard(15,15,'_'){
  rows=15;
  cols=15;
  createPoints();

}


//places a word on the boards
bool Board::place (int rStart, int rEnd, int cStart, int cEnd, string word, int player){
  bool placed=false;
  player=player%2;//if only 2 players
	bool exists, keepGoing=true;//used to determine if a wod can be 	placed
	int points=0,k=0;
	int dblW=0,trplW=0;//for scoring
	int wordValue=0;//for scoring
	const char *l,*tmp;
    tmp = word.c_str();
	//converts word to all upcarse letters
    for(int i = 0;i < word.size();++i) {
        word[i] = toupper(tmp[i]);
    }
	string temp = word;//makes a temporary word to use for checking with the board and bank
 
//----------------------------------------------------
//How does this work
//----------------------------------------------------
    //checks to make sure the length of the word fits start and end
	if((rEnd-rStart)==(word.size()-1)&&(cEnd-cStart)==(word.size()-1))
	{
		keepGoing=false;//if dont try to place the word
	}
	
	//if word goes off the board
	if(keepGoing==false)
	{
        mvprintw(29,16,"Word goes off board");//prints error
        wrefresh(stdscr);
		return placed;
	}

//------------------------------------------------
//to here
//-------------------------------------------------
	
	//checks dictionary to make sure that all the words that would be added are correct
	keepGoing=checkDictionary(rStart, rEnd, cStart, cEnd, word);

	if(keepGoing==false)
	{
        mvprintw(29,16,"Word not in dictionary");//if not in the word then print error
        wrefresh(stdscr);
		return placed;
	}


	//this covers making sure that the letters on the board fits with out word
	if(rStart==rEnd)//in the same row
	{
		for(int i=0; i<(int)temp.size(); i++)//for each letter
		{
			if(letterBoard[rStart][cStart+i]==temp[i])
			{
				temp[i]=' ';//sets that part to blank
			}
			else if(letterBoard[rStart][cStart+i]=='_')
			{
				//does nothing
			}
			else
			{
				keepGoing=false;//so if there is a letter on the word that does not work 
			}
		}
	}
	else//in same column
	{
		for(int i=0; i<(int)temp.size(); i++)//for each letter
		{
			if(letterBoard[rStart+i][cStart]==temp[i])
			{
				temp[i]=' ';//sets that part to blank
			}
			else if(letterBoard[rStart+i][cStart]=='_')
			{
				//does nothing
			}
			else
			{
				keepGoing=false;//so if there is a letter on the word that does not work 
				//with what we want to place then the move won't work
			}
		}
	}
	//if letters do not match with the word we want to make
	if(keepGoing==false)
	{
        mvprintw(29,16,"Letters cannot overlap");//print error
        wrefresh(stdscr);
		return placed;
	}

	//now checks the word to see if we have the remaining letters in the bank
	keepGoing = players[player].place(rStart,rEnd,cStart,cEnd,temp);
	
	if(keepGoing==false)//if not
	{
        mvprintw(29,16,"Don't have the right letters");//print error
        wrefresh(stdscr);
		return placed;
	}

  
 /* if(rStart==rEnd){
    for(int i= cStart;i<cStart+(int)word.size();i++){
      if(letterBoard[rStart][i]!='_'){
	exists=false;
	break;
      }
    }

  }
  else{
     for(int i= rStart;i<(rStart+(int)word.size());i++){
       if(letterBoard[i][cStart]!='_'){
	 exists=false;
	 break;
       }
       
     }
  }*/


  if(keepGoing==true) {
    //the graphical interface of the board

	//outputs the board and figures out the score
    l = word.c_str();
    if(rStart==rEnd){
      //places word horizontally and figures out the word score
      for(int i= cStart;i<cStart+(int)word.size();i++){
	letterBoard[rStart][i]=l[k];
	if(pointsBoard[rStart][i]==2){
	  wordValue=wordValue+2*letterBag.letterValue(l[k]);
	}
	else if(pointsBoard[rStart][i]==3){
	  wordValue=wordValue+3*letterBag.letterValue(l[k]);
	}
	else if(pointsBoard[rStart][i]==4){
	  wordValue=wordValue+letterBag.letterValue(l[k]);
	  dblW=1;
	}

	else if(pointsBoard[rStart][i]==6){
	  wordValue=wordValue+letterBag.letterValue(l[k]);
	  trplW=1;
		}
	else{
	  wordValue=wordValue+letterBag.letterValue(l[k]);
	}
		pointsBoard[rStart][i]=1;
		k++;
    }
      if(trplW==1){
		wordValue=wordValue*3;
      }
      else if(dblW==1){
		wordValue=wordValue*2;
      }	

    }
    else
	{
    //places word vertically and figures out the word score
      for(int i= rStart;i<rStart+(int)word.size();i++)
	  {
	letterBoard[i][cStart]=l[k];
	if(pointsBoard[i][cStart]==2){
	  wordValue=wordValue+2*letterBag.letterValue(l[k]);
	}
	else if(pointsBoard[i][cStart]==3){
	  wordValue=wordValue+3*letterBag.letterValue(l[k]);
	}
	else if(pointsBoard[i][cStart]==4){
	  wordValue=wordValue+letterBag.letterValue(l[k]);
	  dblW=1;
	}

	else if(pointsBoard[i][cStart]==6){
	  wordValue=wordValue+letterBag.letterValue(l[k]);
	  trplW=1;
	}
	else{
	  wordValue=wordValue+letterBag.letterValue(l[k]);
	}
	k++;
	pointsBoard[i][cStart]=1;
      }
      if(trplW==1){
	wordValue=wordValue*3;
      }
      else if(dblW==1){
	wordValue=wordValue*2;
      }	
    }
    players[player].addScore(wordValue);//add points to that players score
    players[player].draw(letterBag);//draws new tiles
    placed=true;
    return placed;//returns that it placed a letter
  }
  else
  {
    mvprintw(29,16,"Word Does Not Exist or Cannot Be Placed");//prints that it couldn't place a letter
    wrefresh(stdscr);
    return placed=true;
  }
}



//returns a word outlined by the r and c coordinates
string Board::getWord(int rStart, int rEnd, int cStart, int cEnd)
{
	//appends letters from the board onto the word string and then returns it
	string word;
	if(rStart==rEnd)//same row
	{
		for(int i=cStart; i<=cEnd; i++)
			word+=letterBoard[rStart][i];//appends chars to string
	}
	else//same column
	{
		for(int i=rStart; i<=rEnd; i++)
			word+=letterBoard[i][cStart];;//appends chars to string
	}
	  
  return word;
}

//either draws or exchanges letters for the player
void Board::draw(bool choice,int player,string ex){
  if(choice==true){//if true you draw
    players[player].draw(letterBag);
  }
  else{//if false you exchagne letters
    players[player].exchange(letterBag,ex);
  }
}


//displays the players bank
void Board::displayBanks(int player){
  players[player].displayBank();
  mvprintw(8,9,"%d",players[0].Score());
  mvprintw(10,9,"%d",players[1].Score());
}


//hard codes the points on the board
void Board::createPoints(){
  //triple word score
  pointsBoard[0][0]=6;
  pointsBoard[0][7]=6;
  pointsBoard[0][14]=6;
  pointsBoard[7][0]=6;
  pointsBoard[7][14]=6;
  pointsBoard[14][0]=6;
  pointsBoard[14][7]=6;
  pointsBoard[14][14]=6;

  //double word score
  pointsBoard[1][1]=4;
  pointsBoard[2][2]=4;
  pointsBoard[3][3]=4;
  pointsBoard[4][4]=4;
  pointsBoard[7][7]=4;
  pointsBoard[10][10]=4;
  pointsBoard[11][11]=4;
  pointsBoard[12][12]=4;
  pointsBoard[13][13]=4;
  pointsBoard[1][13]=4;
  pointsBoard[2][12]=4;
  pointsBoard[3][11]=4;
  pointsBoard[4][10]=4;
  pointsBoard[13][1]=4;
  pointsBoard[12][2]=4;
  pointsBoard[11][3]=4;
  pointsBoard[10][4]=4;

  //triple letter score
  pointsBoard[1][5]=3;
  pointsBoard[1][9]=3;
  pointsBoard[5][1]=3;
  pointsBoard[9][1]=3;
  pointsBoard[5][5]=3;
  pointsBoard[9][9]=3;
  pointsBoard[5][9]=3;
  pointsBoard[5][13]=3;
  pointsBoard[5][5]=3;
  pointsBoard[9][9]=3;
  pointsBoard[9][5]=3;
  pointsBoard[9][13]=3;
  pointsBoard[9][5]=3;
  pointsBoard[13][5]=3;
  pointsBoard[13][9]=3;

  //double letter score
  pointsBoard[0][3]=2;
  pointsBoard[0][11]=2;
  pointsBoard[2][6]=2;
  pointsBoard[2][8]=2;
  pointsBoard[3][0]=2;
  pointsBoard[3][7]=2;
  pointsBoard[3][14]=2;
  pointsBoard[6][2]=2;
  pointsBoard[6][6]=2;
  pointsBoard[6][8]=2;
  pointsBoard[6][12]=2;
  pointsBoard[7][3]=2;
  pointsBoard[7][11]=2;
  pointsBoard[8][2]=2;
  pointsBoard[8][6]=2;
  pointsBoard[8][8]=2;
  pointsBoard[8][12]=2;
  pointsBoard[11][0]=2;
  pointsBoard[11][7]=2;
  pointsBoard[11][14]=2;
  pointsBoard[12][6]=2;
  pointsBoard[12][8]=2;
  pointsBoard[14][3]=2;
  pointsBoard[14][11]=2;


}

//displays both boards
void Board::displayBoard(){
  //draw the board in its entirity
  win = subwin(stdscr,pointsBoard.rows()+2,2*(pointsBoard.cols()+2),5,20);
  box(win,'|','-');
  wrefresh(win);
  init_pair(1,COLOR_RED,COLOR_BLACK);
  init_pair(2,COLOR_BLUE,COLOR_BLACK);
  init_pair(3,COLOR_CYAN,COLOR_BLACK);
  init_pair(4,COLOR_WHITE,COLOR_BLACK);
  for(int i = 0;i<pointsBoard.rows();++i) 
      for(int j = 0;j<pointsBoard.cols();++j) {
          if(pointsBoard[i][j] == 6) {
              attron(COLOR_PAIR(1));
              mvprintw(i+6,2*j+22,"*");
              attroff(COLOR_PAIR(1));
          }
          else if(pointsBoard[i][j] == 2) {
              attron(COLOR_PAIR(3));
              mvprintw(i+6,2*j+22,"*");
              attroff(COLOR_PAIR(3));
          }
          else if(pointsBoard[i][j] == 4) {
              attron(COLOR_PAIR(4));
              mvprintw(i+6,2*j+22,"*");
              attroff(COLOR_PAIR(4));
          }
          else if(pointsBoard[i][j] == 3) {
              attron(COLOR_PAIR(2));
              mvprintw(i+6,2*j+22,"*");
              attroff(COLOR_PAIR(2));
          }
          else {
          }
      }

  init_pair(5,COLOR_GREEN,COLOR_BLACK);
  for(int i = 0;i<letterBoard.rows();++i) 
      for(int j = 0;j<letterBoard.cols();++j) {
          if(letterBoard[i][j] != '_') {
              attron(COLOR_PAIR(5));
              mvprintw(i+6,2*j+22,"%c",letterBoard[i][j]);
              attroff(COLOR_PAIR(5));
          }
      }

  wrefresh(win);
}

bool Board::checkDictionary(int rStart, int rEnd, int cStart, int cEnd, string word)
{
	//checks original word
	string temp;
	if(Dictionary.search(word)==false)
	{
		return false;
	}


	
	if(rStart==rEnd)//in same row
	{
		for(int i=cStart; i<=cEnd; i++)//checks along the length for new words
		{
			int start=rStart-1, end=rEnd+1;
			if(start>=0)//prevents it from going below 0				{	
				while(letterBoard[start][i]!='_')//while not empty
				{
					start--;//keeps going up
					if(start<0)
					{
						break;
					}						
				}
			}
			start++;
			if(end<=14)//stays within 14
			{
				while(letterBoard[end][i]!='_')//while downward not empty
				{
					end++;
					if(end>14)
					{
						break;
					}
				}
					end--;
			}
			if(start<rStart)//if the word goes from top til the added word
			{
				temp+=getWord(start, rStart-1, i, i);//grab the word
			}
			temp+=word[i-cStart];//add the letter from the added word
			if(end>rEnd)//if the word continues down
			{
				temp+=getWord(rEnd+1, end, i, i);//add the part that goes below the added word
			}
			if((int)temp.size()>1)//if there are letters besides the one from the newly added word
			{
				if(Dictionary.search(temp)==false)//check the word in the dictionary
				{
					return false;//if false, cannot put word down
				}
			}
			temp.clear();//clears the temp string
		}
	}
	else//all in the same column
	{
		for(int i=rStart; i<=rEnd; i++)//checks along the length for new words
		{
			int start=cStart-1, end=cEnd+1;
			if(start>=0)//prevents it from going below 0
			{	
				while(letterBoard[i][start]!='_')//looks for letters to the left
				{
					start--;
					if(start<0)
					{
						break;
					}						
				}
			}
			start++;
			if(end<=14)//stays within 14//looks for letters to the right
			{
				while(letterBoard[i][end]!='_')
				{
					end++;
					if(end>14)
					{
						break;
					}
				}
				end--;
			}
			if(start<cStart)//add all leters to the left of the new word
			{
				temp+=getWord(i, i, start, cStart-1);
			}
			temp+=word[i-rStart];//add teh letter from the new word
			if(end>cEnd)//add the letters to the right of the new word
			{
				temp+=getWord(i, i, cEnd+1, end);
			}
			if((int)temp.size()>1)//if there are extra letters
			{
				if(Dictionary.search(temp)==false)//check the word created to see if it is also a word
				{
					return false;//if not return false
				}
			}
			temp.clear();//clears the string
		}
	}
	return true;//if everything passes you can add the word
}

bool Board::middleCovered()//if the middle of the board is covered (has a letter on it) then it is true
{
  if(letterBoard[7][7]!='_')
    return true;
  else
    return false;
}

bool Board::bagEmpty()//returns if letterbag is empty
{
  return letterBag.isEmpty();
}

bool Board::bankEmpty()//returns if a players bank is empty
{
  bool empty=false;
  if(players[0].empty()==true || players[1].empty()==true){
    empty=true;
  }
  return empty;
}

int Board :: winner(){//returns which player has the higher score
  if(players[0].Score()>=players[1].Score()){
    return 1;
  }
  else{
    return 2;
  }
}
