/*      XLeScrabble
        moves.c
        move validation and scoring routines
        By csuos@warwick.ac.uk
*/

#include "scrab.h"
#include "globals.h"

void convupper(char *str)
{
	int conv = 0;
	
	while (str[conv] != '\0')
	{
		str[conv] = toupper((int)str[conv]);
		conv++;
	}
}

unsigned int emptyboard(char b[BOARDSIZE][BOARDSIZE])
{
	int x,y;
	int empty = 1;
	for (x = 0; x < BOARDSIZE; x++)
		for (y = 0; y < BOARDSIZE; y++)
			{
				if (b[x][y] != ' ')
			 		empty = 0;
			 }
	return empty;
}

int validate(char newboard[BOARDSIZE][BOARDSIZE],int testing, int *goscore)
{
	int checkx,checky;
	int sx,sy,ex,ey;
	int finish = 0; /* set finished flag to false */
	int invalid = 0; /* set invalid flag to false */
	int nothoriz = 1; /* set horizontal check to true */
	int notvert = 1; /* set vertical check to true */
	int oldpiece = 0; /* set old piece check to false */
	int csx,csy,cex,cey,empty;
	
	empty = emptyboard(board);
	
	/* find first new letter */
	checkx = checky = 0;
	while (!((board[checkx][checky] == ' ') && (newboard[checkx][checky] != ' '))
		&& (!finish))
	{
		checkx++;
		if (checkx == BOARDSIZE)
			{ checkx = 0;
			  checky++; }
		if (checky == BOARDSIZE)
			finish = 1; /* set finished flag to true */
	}
	if (finish) return HORLICKS;
	/* return invalid if new pieces are not added */
	else
		{ sx=checkx; sy=checky; }
	
	/* check for a horizontal word */
	if ((checkx+1 < BOARDSIZE) && (newboard[checkx+1][checky] != ' '))
	{
		/* find end of horizontal , including old pieces*/
		while ((checkx+1 < BOARDSIZE) &&
		 (newboard[checkx+1][checky] != ' '))
		 {
			if (board[checkx+1][checky] == ' ')
				{ nothoriz = 0; }
			checkx++;
		 }
		 if (!nothoriz)
		 {
			 ex = checkx;
			 ey = checky;
		 
		/* check for no extra pieces */
		checkx++;
		if (checkx == BOARDSIZE)
			{ checkx = 0 ; checky++; }
		while ((checky < BOARDSIZE) && (!invalid))
			{
				if ((board[checkx][checky] == ' ') &&
				    (newboard[checkx][checky] != ' '))
				   invalid = 1; /* go is invalid */
				else {
					checkx++;
					if (checkx == BOARDSIZE)
						{ checkx = 0 ; checky++; }
				}
			}
		if (invalid)
			return HORLICKS;
		else
			{
			if (!empty)
			/* check to see if there is an old piece around word */
			{
			csx = sx;
			cex = ex;
			if (sy > 0) csy = sy-1;
			else csy = sy;
			if (ey < BOARDSIZE-1) cey = ey+1;
			else cey = ey;
			for (checkx = csx; checkx <= cex; checkx++)
				for (checky = csy; checky <= cey; checky++)
					if (board[checkx][checky] != ' ')
						oldpiece = 1;
			if ((sx > 0)&&(board[sx-1][sy]!=' '))
				oldpiece = 1;
			if ((ex < BOARDSIZE-1)&&(board[ex+1][ey]!=' '))
				oldpiece = 1;
			if (oldpiece)
			return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
			else
				return HORLICKS;
			}
			else
				return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
			}
		}
	}
	checkx = sx;
	checky = sy;
		/* check for a vertical word */
		if ((checky+1 < BOARDSIZE) && (newboard[checkx][checky+1] != ' ')
			&& nothoriz)
		{

			/* check for no extra pieces before vertical word */
			checky++;
			checkx = 0;
			while ((checkx < sx) && (!invalid))
			{
				if ((board[checkx][checky] == ' ') &&
				    (newboard[checkx][checky] != ' '))
				   invalid = 1; /* extra piece, go is invalid */
				else {
					checky++;
					if (checky == BOARDSIZE)
						{ checky = sy+1; checkx++; }
					}
			}
			if (invalid)
				return HORLICKS;
			/* reset check variables */
			checkx=sx; checky=sy;
			
			/* now find end of vertical word */
			while ((checky+1 < BOARDSIZE) &&
		 		(newboard[checkx][checky+1] != ' '))
		 	{
				if (board[checkx][checky+1] == ' ')
					{ notvert = 0; }
				checky++;
		 	}
		 	
		 	if (!notvert)
		 	{
		 	ex = checkx;
			ey = checky;
			
			/* check for no extra pieces after vertical word */
			checky++;
			if (checky == BOARDSIZE)
				{ checky = sy; checkx ++; }		
			while ((checkx < BOARDSIZE) && (!invalid))
				{
					if ((board[checkx][checky] == ' ') &&
					    (newboard[checkx][checky] != ' '))
					   invalid = 1; /* go is invalid */
					else {
						checky++;
						if (checky == BOARDSIZE)
							{ checky = sy ; checkx++; }
					}
				}
			if (invalid)
				return HORLICKS;
			else
			{
			if (!empty)
			{			
				csy = sy;
				cey = ey;
				if (sx > 0) csx = sx-1;
				else csx = sx;
				if (ex < BOARDSIZE-1) cex = ex+1;
				else cex = ex;
				for (checkx = csx; checkx <= cex; checkx++)
					for (checky = csy; checky <= cey; checky++)
						if (board[checkx][checky] != ' ')
							oldpiece = 1;
				if ((sy > 0)&&(board[sx][sy-1]!=' '))
					oldpiece = 1;
				if ((ey < BOARDSIZE-1)&&(board[ex][ey+1]!=' '))
					oldpiece = 1;
				if (oldpiece)
					return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
				else
					return HORLICKS;
			}
			else
				return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
			}
			}
		}
			if (notvert && nothoriz)
			{	/* one letter */
				ex = sx; ey = sy;
				/* check for no extra letters */
				checkx++;
				if (checkx == BOARDSIZE)
					{ checkx = 0; checky++; }
				while ((checky < BOARDSIZE) && (!invalid))
				{
					if ((board[checkx][checky] == ' ') &&
					    (newboard[checkx][checky] != ' '))
					   invalid = 1; /* go is invalid */
					else {
						checkx++;
						if (checkx == BOARDSIZE)
							{ checkx = 0; checky++; }
					}
				}
			if (invalid)
				return HORLICKS;
			else
			{
			/* check to see if there is at least one surrounding piece */
			if (((sy > 0)&&(board[sx][sy-1]!=' '))||
			    ((sy < BOARDSIZE-1)&&(board[sx][sy+1]!=' '))||
			    ((sx > 0)&&(board[sx-1][sy]!=' '))||
			    ((sx < BOARDSIZE-1)&&(board[sx+1][sy]!=' ')))
				return (checkwords(newboard,sx,sy,ex,ey,testing,goscore));
			else
				return HORLICKS;
			}
			}
	return HORLICKS; /* just in case */
}


int checkwords(char nb[BOARDSIZE][BOARDSIZE],int sx,int sy,int ex,int ey,int testing,int *goscore)
{
	int checkx,checky,lefttile,righttile,toptile,bottile;
	int indict,fillword;
	char checkword[16];
	int correct = 1;
	int loneletter = 0;
	char wordsmade[BESTGOWORDSLEN] = "";
	int wordpos = 0;
	
	/* initialise go score */
	*goscore = 0;
	
	/* if first go check to see if it passes through centre */
	if (emptyboard(board))
	{
		/* if horizontal word */
		if (ey-sy == 0)
		{
			if (!((sx <= 7) && (ex >= 7) && (sy == 7)))
				return NOTCENTRE;
		}
		else
		/* if vertical word */
		{
			if (!((sy <= 7) && (ey >= 7) && (sx == 7)))
				return NOTCENTRE;
		}
	}
	
	/* check for horizontal word */
	if (ey-sy == 0)
	{
		/* ####check left and right for complete word#### */
		
		/* check left */
		checkx = sx;
		while (((checkx-1) >= 0) && (board[checkx-1][sy] != ' '))
		{
			checkx--;
		}
		lefttile = checkx;
		
		/* check right */
		checkx = ex;
		while (((checkx+1) < BOARDSIZE) && (board[checkx+1][sy] != ' '))
		{
			checkx++;
		}
		righttile = checkx;

		/* do not check if it is one letter */
		if (!((lefttile == sx)&&(righttile == sx)))
		{		
			/* construct word */
			for (fillword=lefttile; fillword <= righttile; fillword++)
			{
				checkword[fillword-lefttile] = nb[fillword][sy];	
			}
			checkword[fillword-lefttile]='\0';
		
			/* and check it */
			convupper(checkword);
			if (!testing)
				indict = wordsearch(checkword);
			else
				indict = 1;
			correct = correct&&indict;
			if (indict)
				{ 
				*goscore += scoreword(lefttile,sy,righttile,sy,nb);
				if ((wordpos+strlen(checkword)+1)<BESTGOWORDSLEN)
				{
					if (wordpos != 0)
						strcat(wordsmade,",");
					wordpos+=strlen(checkword)+1;
					strcat(wordsmade,checkword);
				}
				}
		}
		else
			{ loneletter = 1; }

		/* #####check up and down along word#### */
		checkx = sx;

		/* move along letters */
		while ((checkx <= ex)&&correct)
		{
		/* only check and score new words */
		if (board[checkx][sy] == ' ')
			{
			/* check up */
			checky = sy;		
			while (((checky-1) >= 0) && (board[checkx][checky-1] != ' '))
			{
				checky--;
			}
			toptile = checky;
			
			/* check down */
			checky = sy;
			while (((checky+1) < BOARDSIZE) && (board[checkx][checky+1] != ' '))		
			{
				checky++;
			}
			bottile = checky;


			/* do not check if it is one letter */
			if (!((toptile == sy)&&(bottile == sy)))
			{
				/* construct word */
				for (fillword=toptile; fillword <= bottile; fillword++)
				{
					checkword[fillword-toptile] = nb[checkx][fillword];
				}
				checkword[fillword-toptile]='\0';
				
				/* and check it */
				convupper(checkword);
				if (!testing)
					{
					indict = wordsearch(checkword);
					}
				else
					indict = 1;
				correct = correct&&indict;
				if (indict)
					{
					*goscore += scoreword(checkx,toptile,checkx,bottile,nb);
					if ((wordpos+strlen(checkword)+1)<BESTGOWORDSLEN)
					{
						if (wordpos != 0)
							strcat(wordsmade,",");
						wordpos+=strlen(checkword)+1;
						strcat(wordsmade,checkword);
					}
					}
			}
			else
			{
				if (loneletter)
					correct = 0;
				/* if this is an "island" then it is not a word */
			}
			}
			checkx++;
		}
		if (correct)
		{
			if (!testing) alterbestgo(*goscore,wordsmade);
			return VALID;
		}
		else
			return INVALID;
	}
	else
	/*### check up and down for complete word ###*/
	{
		/* check up */
		checky = sy;
		while (((checky-1) >= 0) && (board[sx][checky-1] != ' '))
		{
			checky--;
		}
		toptile = checky;
		
		/* check down */
		checky = ey;
		while (((checky+1) < BOARDSIZE) && (board[sx][checky+1] != ' '))
		{
			checky++;
		}
		bottile = checky;
		
		/* no need to check for lone letter, already checked */
		/* construct word */
		for (fillword=toptile; fillword <= bottile; fillword++)
		{
			checkword[fillword-toptile] = nb[sx][fillword];	
		}
		checkword[fillword-toptile]='\0';
		
		/* and check it */
		convupper(checkword);
		if (!testing)
			indict = wordsearch(checkword);
		else
			indict = 1;
		correct = correct && indict;	
		if (indict)
		{
		*goscore += scoreword(sx,toptile,sx,bottile,nb);
		if ((wordpos+strlen(checkword)+1)<BESTGOWORDSLEN)
			{
				if (wordpos != 0)
					strcat(wordsmade,",");
				wordpos+=strlen(checkword)+1;
				strcat(wordsmade,checkword);
			}
		}
		
		/* ####check left and right along word#### */
		checky = sy;
		
		/* move along letters */
		while ((checky <= ey) && correct)
		{
		/* only check and score new words */
		if (board[sx][checky] == ' ')
			{
			/* check left */
			checkx = sx;
			while (((checkx-1) >= 0) && (board[checkx-1][checky] != ' '))
			{
				checkx--;
			}
			lefttile = checkx;
			
			/* check right */
			checkx = sx;
			while (((checkx+1) < BOARDSIZE) && (board[checkx+1][checky] != ' '))
			{
				checkx++;
			}
			righttile = checkx;
			
			/* do not check if it is one letter */
			if (!((lefttile == sx)&&(righttile == sx)))
			{
				/* construct word */
				for (fillword=lefttile; fillword <= righttile; fillword++)
				{
					checkword[fillword-lefttile] = nb[fillword][checky];
				}
				checkword[fillword-lefttile]='\0';
				
				/* and check it */
				convupper(checkword);
				if (!testing)
					indict = wordsearch(checkword);
				else
					indict = 1;
				correct = correct&&indict;
				if (indict)
				{
				*goscore += scoreword(lefttile,checky,righttile,checky,nb);
				if ((wordpos+strlen(checkword)+1)<BESTGOWORDSLEN)
					{
						if (wordpos != 0)
							strcat(wordsmade,",");
						wordpos+=strlen(checkword)+1;
						strcat(wordsmade,checkword);
					}
				}
			}
			}
			checky++;
		}
		if (correct)
		{
			if (!testing) alterbestgo(*goscore,wordsmade);
			return VALID;
		}
		else
			return INVALID;
				
	}

	return 0; /* just in case */
}


int scoreword(int sx,int sy,int ex,int ey, char nb[BOARDSIZE][BOARDSIZE])
{
	int wordscore = 0;
	int multiple = 1;
	int scorex,scorey;
	int numlett = 0,goscore = 0;
	
	/* score horizontal */
	if ((sy - ey) == 0)
	{
		for (scorex = sx; scorex <= ex; scorex++)
		{
			
			
			/* score letter & bonus */
			if (isupper(nb[scorex][sy]))
			{
			wordscore = wordscore + letterscore[nb[scorex][sy]-'A'];

			/* do not score for old pieces */
			if (board[scorex][sy] == ' ')
			{
			switch (sq_col[scorex][sy])
			{
			case 1 : /* double letter */
				{ wordscore += letterscore[nb[scorex][sy]-'A']; break;}
			case 2 : /* tripple letter */
				{ wordscore += (2*letterscore[nb[scorex][sy]-'A']); break;}
			default : {break;}
			}
			}
			}
			
			/* check for word bonus */
			if (board[scorex][sy] == ' ')
			{
			switch (sq_col[scorex][sy])
			{
			case 3 : /* double word */
				{ multiple *= 2 ; break;}
			case 4 : /* double word */
				{ multiple *= 3 ; break;}
			default : {break;}
			}
			/* and finally check to see if seven letters are used */
			numlett++;
			}	
		}
		goscore = wordscore*multiple;
		if (numlett == 7)
			goscore += 50;
		return (goscore);
	}
	else
	{
		for (scorey = sy; scorey <= ey; scorey++)
		{			
			/* score letter & bonus */
			if (isupper(nb[sx][scorey])) 
			{
			wordscore += letterscore[nb[sx][scorey]-'A'];

			/* do not score for old pieces */
			if (board[sx][scorey] == ' ')
			{
			switch (sq_col[sx][scorey])
			{
			case 1 : /* double letter */
				{ wordscore += letterscore[nb[sx][scorey]-'A']; break;}
			case 2 : /* tripple letter */
				{ wordscore += (2*letterscore[nb[sx][scorey]-'A']); break;}
			default : {break;}
			}
			}
			}
			
			/* check for word bonus */
			if (board[sx][scorey] == ' ')
			{
			switch (sq_col[sx][scorey])
			{
			case 3 : /* double word */
				{ multiple *= 2 ; break;}
			case 4 : /* double word */
				{ multiple *= 3 ; break;}
			default : {break;}
			}
			/* and finally check to see if seven letters are used */
			numlett++;
			}	
		}
		goscore = wordscore*multiple;
		if (numlett == 7)
			goscore += 50;
		return (goscore);
	}
	return 0;
}


/* debug routines */

void addhword(char newboard[BOARDSIZE][BOARDSIZE],int x,int y,char *word,int length)
{
	int add;
	for (add = 0; add < length; add++)
	{
		newboard[x][y] = word[add];
		x++;
	}	
}

void addvword(char newboard[BOARDSIZE][BOARDSIZE],int x,int y,char *word,int length)
{
	int add;
	for (add = 0; add < length; add++)
	{
		newboard[x][y] = word[add];
		y++;
	}	
}


/* end of debug routines */

