/*      XLeScrabble
        cmove.c
        computer player
        By csuos@warwick.ac.uk
*/

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

int check_boardh(int x,int y,int numlett)
{
    int pieces = 0;
    int checkx = x,checky = y;
    char valboard[BOARDSIZE][BOARDSIZE];
    int vx,vy,dummy;
    
    for (vx = 0; vx < BOARDSIZE; vx++)
	for (vy = 0; vy < BOARDSIZE; vy++)
	    valboard[vx][vy] = board[vx][vy];

    assert(checky < BOARDSIZE);
    while (checkx < x+numlett)
    {
	assert(checkx < BOARDSIZE);
	if (board[checkx][checky] == ' ')
	    valboard[checkx][checky] = '*';
	else
	    pieces++;
	checkx++;
    }
    /* ignore words already there */
    if (pieces == numlett)
	return INVALID;
    else
	return validate(valboard,1,&dummy);	
}

int check_boardv(int x, int y,int numlett)
{
    int pieces = 0;
    int checkx = x,checky = y;
    char valboard[BOARDSIZE][BOARDSIZE];
    int vx,vy,dummy;
	
    for (vx = 0; vx < BOARDSIZE; vx++)
	for (vy = 0; vy < BOARDSIZE; vy++)
	    valboard[vx][vy] = board[vx][vy];
	
    assert(checkx < BOARDSIZE);
    while (checky < y+numlett)
    {
	assert(checky < BOARDSIZE);
	if (board[checkx][checky] == ' ')
	    valboard[checkx][checky] = '*';
	else
	    pieces++;
	checky++;
    }
    /* ignore 4 letter words already there */
    if (pieces == numlett)
	return INVALID;
    else
	return validate(valboard,1,&dummy);
}

void makeperm(short int p[7][5040][7],int num[7])
{
#ifdef MAKEPERMS
    int used[7];
    int ptr[7];
    int count;
    int clash,max;
    int lastptr[7] = {-1,-1,-1,-1,-1,-1,-1};
	
    for (count = 0; count < 7; count++)
	num[count] = 0;
    for (max = 0; max < 7; max++)
    {
	for (ptr[0] = 0; ptr[0] < 7; ptr[0]++)
	    for (ptr[1] = 0; ptr[1] < 7; ptr[1]++)
		for (ptr[2] = 0; ptr[2] < 7; ptr[2]++)
		    for (ptr[3] = 0; ptr[3] < 7; ptr[3]++)
			for (ptr[4] = 0; ptr[4] < 7; ptr[4]++)
			    for (ptr[5] = 0; ptr[5] < 7; ptr[5]++)
				for (ptr[6] = 0; ptr[6] < 7; ptr[6]++)
				{
				    for (count = 0; count < 7; count++)
				    {
					used[count] = 0;
				    }
		
				    clash = 0;
				    for (count = 0; count < (max+1); count++)
					if (!used[ptr[count]])
					    used[ptr[count]] = 1;
					else
					{
					    clash = 1;
					    break;
					}
				    if (clash)
					continue;
				    clash = 0;
				    for (count = 0; count < (max+1); count++)
				    {
					if (ptr[count] == lastptr[count])
					    clash++;	
				    }
				    if (clash == (max+1))
					continue;
				    for (count = 0; count < (max+1); count++)
				    {
					assert(max < 7);
					assert(num[max] < 5040);
					assert(count < 7);
					p[max][num[max]][count] = ptr[count];
					lastptr[count] = ptr[count];
				    }
				    (num[max])++;
				}
    }
#else
    loadperms();
#endif
    /* MAKEPERMS */
}

extern void findh_blank(int numblanks,char word[16],int xpos,int ypos,
			int *curr_bestscore,char curr_bestword[16],
			char tempboard[BOARDSIZE][BOARDSIZE],char prefix[16],
			int numlett)
{
    int count,scount;
    char blanktiles[NUMBLANKS] = BLANKTILES;
    int c,fblankpos = -1,sblankpos = -1,wordlength,indict,checkx;
    int currscore,foundfirst,foundsecond,valid;
    char checkdict[16],temp[16];
	
    /* using slow loop method!!! */
    wordlength = strlen(word);
    if (numblanks == 1)
	/* find words for 1 blank */
    {
	for (c = 0;c <= wordlength;c++)
	    if (word[c] == '*')
		fblankpos = c;
	for (count = 0;count < NUMBLANKS;count++)
	{
	    assert(fblankpos < 16);
	    word[fblankpos] = blanktiles[count];
			
	    strcpy(temp,prefix);
	    strcpy(checkdict,strcat(temp,word));
	    convupper(checkdict);
	    indict = wordsearch(checkdict);
	    if (indict)
	    {
		/* insert the letters on the temp board */
		for (checkx = xpos; checkx < xpos+numlett; checkx++)
		{
		    assert(checkx < BOARDSIZE);
		    assert(ypos < BOARDSIZE);
		    tempboard[checkx][ypos] = word[checkx-xpos];
		}
		/* now check all words created */
		valid = checkwords(tempboard,xpos,ypos,xpos+wordlength-1,ypos,0,&currscore);
		if ((valid == VALID)&&(currscore > *curr_bestscore))
		{
		    *curr_bestscore = currscore;
		    strcpy(curr_bestword,word);
		}
	    }
	}
    }
    else
	/* find words for 2 blanks */
    {
	c = 0; foundfirst = 0; foundsecond = 0;
	while ((c <= wordlength)&&(!foundsecond))
	{
	    if (word[c] == '*')
	    {
		if (!foundfirst)
		{
		    fblankpos = c;
		    foundfirst = 1;
		}
		else
		{
		    sblankpos = c;
		    foundsecond = 1;
		}
	    }
	    c++;
	}
		
	for (count = 0;count < NUMBLANKS;count++)
	    for (scount = 0;scount < NUMBLANKS;scount++)
	    {
		assert(fblankpos < 16);
		assert(sblankpos < 16);
		word[fblankpos] = blanktiles[count];
		word[sblankpos] = blanktiles[scount];
		strcpy(temp,prefix);
		strcpy(checkdict,strcat(temp,word));
		convupper(checkdict);
		indict = wordsearch(checkdict);
		if (indict)
		{
		    /* insert the letters on the temp board */
		    for (checkx = xpos; checkx < xpos+numlett; checkx++)
		    {
			assert(checkx < BOARDSIZE);
			assert(ypos < BOARDSIZE);
			tempboard[checkx][ypos] = word[checkx-xpos];
		    }
		    /* now check all words created */
		    valid = checkwords(tempboard,xpos,ypos,xpos+wordlength-1,ypos,0,&currscore);
		    if ((valid == VALID)&&(currscore > *curr_bestscore))
		    {
			*curr_bestscore = currscore;
			strcpy(curr_bestword,word);
		    }
		}
	    }
    }
}

extern void findv_blank(int numblanks,char word[16],int xpos,int ypos,
			int *curr_bestscore,char curr_bestword[16],
			char tempboard[BOARDSIZE][BOARDSIZE],char prefix[16],
			int numlett)
{
    int count,scount;
    char blanktiles[NUMBLANKS] = BLANKTILES;
    int c,fblankpos = -1,sblankpos = -1,wordlength,indict,checky;
    int currscore,foundfirst,foundsecond,valid;
    char checkdict[16],temp[16];
	
    /* using slow loop method!!! */
    wordlength = strlen(word);
    if (numblanks == 1)
	/* find words for 1 blank */
    {
	for (c = 0;c <= wordlength;c++)
	    if (word[c] == '*')
		fblankpos = c;
	for (count = 0;count < NUMBLANKS;count++)
	{
	    assert(fblankpos < 16);
	    word[fblankpos] = blanktiles[count];
			
	    strcpy(temp,prefix);
	    strcpy(checkdict,strcat(temp,word));
	    convupper(checkdict);
	    indict = wordsearch(checkdict);
	    if (indict)
	    {
		/* insert the letters on the temp board */
		for (checky = ypos; checky < ypos+numlett; checky++)
		{
		    assert(checky < BOARDSIZE);
		    assert(xpos < BOARDSIZE);
		    tempboard[xpos][checky] = word[checky-ypos];
		}
		/* now check all words created */
		valid = checkwords(tempboard,xpos,ypos,xpos,ypos+wordlength-1,0,&currscore);
		if ((valid == VALID)&&(currscore > *curr_bestscore))
		{
		    *curr_bestscore = currscore;
		    strcpy(curr_bestword,word);
		}
	    }
	}
    }
    else
	/* find words for 2 blanks */
    {
	c = 0; foundfirst = 0; foundsecond = 0;
	while ((c <= wordlength)&&(!foundsecond))
	{
	    if (word[c] == '*')
	    {
		if (!foundfirst)
		{
		    fblankpos = c;
		    foundfirst = 1;
		}
		else
		{
		    sblankpos = c;
		    foundsecond = 1;
		}
	    }
	    c++;
	}

	for (count = 0;count < NUMBLANKS;count++)
	    for (scount = 0;scount < NUMBLANKS;scount++)
	    {
		assert(fblankpos < 16);
		assert(sblankpos < 16);
		word[fblankpos] = blanktiles[count];
		word[sblankpos] = blanktiles[scount];
					
		strcpy(temp,prefix);
		strcpy(checkdict,strcat(temp,word));
		convupper(checkdict);
		indict = wordsearch(checkdict);
		if (indict)
		{
		    /* insert the letters on the temp board */
		    for (checky = ypos; checky < ypos+numlett; checky++)
		    {
			assert(checky < BOARDSIZE);
			assert(xpos < BOARDSIZE);
			tempboard[xpos][checky] = word[checky-ypos];
		    }
		    /* now check all words created */
		    valid = checkwords(tempboard,xpos,ypos,xpos,ypos+wordlength-1,0,&currscore);
		    if ((valid == VALID)&&(currscore > *curr_bestscore))
		    {
			*curr_bestscore = currscore;
			strcpy(curr_bestword,word);
		    }
		}
	    }
    }
}

void checkh_words(int x, int y,char best[16],int *bestscore,int numlett)
{
    char test[16], dummy[16],temp[16];
    int locked[8] = {0,0,0,0,0,0,0,0};
    int checkx;
    int maxlett = numlett;
    int inslett;
    int indict;
    char tempboard[BOARDSIZE][BOARDSIZE];
    int bx,by;
    int count,rev;
    int currscore;
    int num_perm,wordlen,valid;
    int blank; /* represents whether there is a blank in the word */
    int space; /* represents whether there is a space in the bar */

    *bestscore = 0;
	
    /* make a copy of board */
    for (bx = 0; bx < BOARDSIZE; bx++)
	for (by = 0; by < BOARDSIZE; by++)
	    tempboard[bx][by]=board[bx][by];

    /* lock the tiles in the test word */
    for (checkx = x; checkx < x+numlett; checkx++)
    {
	if ((checkx < BOARDSIZE)&&(board[checkx][y] != ' '))
	{
	    assert((checkx-x) < 16);
	    test[checkx-x] = board[checkx][y];
	    assert((checkx-x) < 8);
	    locked[checkx-x] = 1;
	    maxlett--;
	}
    }

    /* create a string containing the letters before the word */
    if ((x-1 >= 0)&&(board[x-1][y] != ' '))
    {
	count = 1;
	while ((x-count >= 0)&&(board[x-count][y] != ' '))
	{
	    count++;
	}
	count--;
	for (rev = count;rev > 0;rev--)
	{
	    assert((count - rev) < 16);
	    dummy[count-rev] = board[x-rev][y];
	}
	assert(count < 16);
	dummy[count] = '\0';
    }
    else
	dummy[0]='\0';
	
    num_perm = numperms[maxlett-1];

    for (count = 0; count < num_perm; count++)
    {
	ProcessEvent();
	
	/* insert the letters in the test word */
	inslett = 0;
	blank = 0;
	space = 0;
	for (checkx = 0; checkx < numlett; checkx++)
	{
	    if (!locked[checkx])
	    {
		assert(checkx < 16);
		test[checkx] = player[curr_player].bar[perms[maxlett-1][count][inslett++]];
		if (test[checkx] == '*')
		    blank++;
		if (test[checkx] == ' ')
		    space++;
	    }
	    /* cycles lettptr array, depending of number of letters to
	       place (maxlett), and letter just placed */
	}
	

	/* if the word created contains a space end immediately */
	if (!space)
	{

	    /* fill in the letters after the word placed */
	    while ((x+checkx < BOARDSIZE)&&(board[x+checkx][y] != ' '))
	    {
		assert(checkx < 16);
		test[checkx] = board[x+checkx][y];
		checkx++;
	    }
	    assert(checkx < 16);
	    test[checkx]='\0';
	    wordlen = checkx-1;

	    /* if there is no blank in the word check normaly*/
	    if (!blank)
	    {
		strcpy(temp,dummy);
		indict = wordsearch(strcat(temp,test));
		if (indict)
		{
		    /* insert the letters on the temp board */
		    for (checkx = x; checkx < x+numlett; checkx++)
		    {
			assert(checkx < BOARDSIZE);
			assert(y < BOARDSIZE);
			tempboard[checkx][y] = test[checkx-x];
		    }
		    /* now check all words created */
		    valid = checkwords(tempboard,x,y,x+wordlen,y,0,&currscore);
			
		    if ((valid == VALID)&&(currscore > *bestscore))
		    {
			*bestscore = currscore;
			strcpy(best,test);
		    }
		}
	    }
	    else
	    {
		/* run words with blanks routine */
		findh_blank(blank,test,x,y,bestscore,best,tempboard,dummy,numlett);
	    }
	    /* next word */
	}
    }
}

void checkv_words(int x, int y,char best[16],int *bestscore,int numlett)
{
    char test[16], dummy[16],temp[16];
    int locked[8] = {0,0,0,0,0,0,0,0};
    int checky;
    int maxlett = numlett;
    int inslett;
    int indict;
    char tempboard[BOARDSIZE][BOARDSIZE];
    int bx,by;
    int count,rev;
    int currscore;
    int num_perm,wordlen,valid;
    int blank; /* represents whether there is a blank in the word */
    int space; /* represents whether there is a space in the bar */
	
    *bestscore = 0;
	
    /* make a copy of board */
    for (bx = 0; bx < BOARDSIZE; bx++)
	for (by = 0; by < BOARDSIZE; by++)
	    tempboard[bx][by]=board[bx][by];

    /* lock the tiles in the test word */
    for (checky = y; checky < y+numlett; checky++)
    {
	if ((checky < BOARDSIZE)&&(board[x][checky] != ' '))
	{
	    assert((checky-y) < 16);
	    test[checky-y] = board[x][checky];
	    assert((checky-y) < 8);
	    locked[checky-y] = 1;
	    maxlett--;
	}
    }

    /* create a string containing the letters before the word */
    if ((y-1 >= 0)&&(board[x][y-1] != ' '))
    {
	count = 1;
	while ((y-count >= 0)&&(board[x][y-count] != ' '))
	{
	    count++;
	}
	count--;
	for (rev = count;rev > 0;rev--)
	{
	    assert((count-rev) < 16);
	    dummy[count-rev] = board[x][y-rev];
	}
	assert(count < 16);
	dummy[count] = '\0';
    }
    else
	dummy[0]='\0';
	
    num_perm = numperms[maxlett-1];

    for (count = 0; count < num_perm; count++)
    {
	ProcessEvent();
	
	/* insert the letters in the test word */
	inslett = 0;
	blank = 0;
	space = 0;
	for (checky = 0; checky < numlett; checky++)
	{
	    if (!locked[checky])
	    {
		assert(checky < 16);
		test[checky] = player[curr_player].bar[perms[maxlett-1][count][inslett++]];
		if (test[checky] == '*')
		    blank++;
		if (test[checky] == ' ')
		    space++;
	    }
	    /* cycles lettptr array, depending of number of letters to
	       place (maxlett), and letter just placed */
	}
	
	/* if the word created contains a space end immediately */
	if (!space)
	{
	
	    /* fill in the letters after the word placed */
	    while ((y+checky < BOARDSIZE)&&(board[x][y+checky] != ' '))
	    {
		assert(checky < 16);
		test[checky] = board[x][y+checky];
		checky++;
	    }
	    assert(checky < 16);
	    test[checky]='\0';
	    wordlen = checky-1;

	    /* if there is no blank in the word check normaly*/
	    if (!blank)
	    {
		strcpy(temp,dummy);
		indict = wordsearch(strcat(temp,test));
		if (indict)
		{
		    /* insert the letters on the temp board */
		    for (checky = y; checky < y+numlett; checky++)
		    {
			assert(x < BOARDSIZE);
			assert(checky < BOARDSIZE);
			tempboard[x][checky] = test[checky-y];
		    }
		    /* now check all words created */
		    valid = checkwords(tempboard,x,y,x,y+wordlen,0,&currscore);
			
		    if ((valid == VALID)&&(currscore > *bestscore))
		    {
			*bestscore = currscore;
			strcpy(best,test);
		    }
		}
	    }
	    else
	    {
		/* run words with blanks routine */
		findv_blank(blank,test,x,y,bestscore,best,tempboard,dummy,numlett);
	    }
	    /* next word */
	}
    }
}


void comp_move(int *compscore,int level)
{
    int x,y,checkgo;
    char bestword[16],newword[16];
    int bestscore = 0,newscore = 0;
    int bestdir = 0; /* direction of best word 0 = horiz, 1 = vert */
    int bx = -1,by = -1;
    int foundgo = 0;
    int wordlength;
    char lettused[8];
    int used,rembar;
    int randlen;
    int sum,counter;
    int smallestword, largestword;
    float percinc, searchinc, realinc, removeinc, currperc, sizeinc;

    if ((level>0)&&(level < 7))
    {
	randlen = (rand()%norms_max[level-1])+1;
	sum = 0;
	counter = 0;	
	while ((sum < norms_max[level-1]+1)&&(sum < randlen))
	{
	    sum+=norms[level-1][counter];
	    counter++;
	}
	smallestword = counter - (level-1);
	largestword = counter + (level-1);
	if (smallestword < 1) smallestword = 1;
	if (largestword > 7) largestword = 7;
    }
    else
    {
	smallestword = 1;
	largestword = 7;
    }
	
    percinc = 93.0 / (largestword - smallestword + 1.0);
    realinc = 0;
    currperc = 0;
    UpdateComp((int)currperc);

    sizeinc = percinc / (largestword+1-smallestword);
    for (wordlength =smallestword; wordlength < largestword+1; wordlength++)
    {
	searchinc = sizeinc / (BOARDSIZE-wordlength+1);
	for (x=0; x < BOARDSIZE-wordlength+1; x++)
	{
	    ProcessEvent();
	    if (searchinc > 0) UpdateComp((int)currperc);
	    for (y=0; y < BOARDSIZE-wordlength+1; y++)
	    {
		ProcessEvent();
		checkgo = check_boardh(x,y,wordlength);
		if (checkgo == VALID)
		{
		    checkh_words(x,y,newword,&newscore,wordlength);
		    if (newscore > bestscore)
		    {
			strcpy(bestword,newword);
			bx = x; by = y;
			bestscore = newscore;
			bestdir = 0;
			foundgo=1;
		    }
		}
		/*ProcessEvent();*/
		checkgo = check_boardv(x,y,wordlength);
		if (checkgo == VALID)
		{
		    checkv_words(x,y,newword,&newscore,wordlength);
		    if (newscore > bestscore)
		    {
			strcpy(bestword,newword);
			bx = x; by = y;
			bestscore = newscore;
			bestdir = 1;
			foundgo=1;
		    }
		}
	    }
	    currperc += searchinc;
	}
	realinc += percinc;
	currperc = realinc;
	if (searchinc == 0) UpdateComp(currperc);
    }

    /*
    if (foundgo)
    {
	printf("Computer goes ");
	if (bestdir == 0)
	    printf("Horizontaly ");
	else
	    printf("Verticaly ");
	printf("at (%i,%i) with : %s, scoring : %i\n",bx,by,bestword,bestscore);
    }
    else
	printf("Computer cannot go!");
	*/

    /*	currperc = 93.0;*/
    UpdateComp((int)currperc);
	
    if (foundgo)
    {
	lettused[0] = '\0';
	wordlength = strlen(bestword);
	if (bestdir == 0)
	    for(x=bx;x < bx+wordlength;x++)
	    {
		if (board[x][by] == ' ')
		{
		    assert((strlen(lettused)+1) < 8);
		    lettused[strlen(lettused)+1] = '\0';
		    assert(strlen(lettused) < 8);
		    lettused[strlen(lettused)] = bestword[x-bx];
		}
		assert(x < BOARDSIZE);
		assert(by < BOARDSIZE);
		board[x][by] = bestword[x-bx];
	    }
	else
	    for(y=by;y < by+wordlength;y++)
	    {
		if (board[bx][y] == ' ')
		{
		    assert((strlen(lettused)+1) < 8);
		    lettused[strlen(lettused)+1] = '\0';
		    assert(strlen(lettused) < 8);
		    lettused[strlen(lettused)] = bestword[y-by];
		}
		assert(bx < BOARDSIZE);
		assert(y < BOARDSIZE);
		board[bx][y] = bestword[y-by];
	    }
	assert(curr_player < 4);
	player[curr_player].score += bestscore;
	*compscore = bestscore;
	removeinc = 7.0 / strlen(lettused);
	for (used = 0; used < (int)strlen(lettused);used++)
	{
	    for (rembar = 0; rembar < BARLEN;rembar++)
	    {
		if ((islower(lettused[used])&&
		     (player[curr_player].bar[rembar] == '*'))||
		    (player[curr_player].bar[rembar] ==
		     lettused[used]))
		{
		    assert(rembar < BARLEN);
		    player[curr_player].bar[rembar] = ' ';
		    break;
		}
	    }
	    currperc += removeinc;
	    UpdateComp((int)currperc);
	}
	fillbar((int)curr_player);
    }
    else
    {
	*compscore = 0;
    }
    UpdateComp(100);
}
