/*
 *      XCountdown - X version of the popular Channel 4 quiz show
 *
 * This software comes with NO warranty whatsoever. I therefore take no
 * responsibility for any damages, losses or problems caused through use
 * or misuse of this program.
 *
 * I hereby grant permission for this program to be freely copied and
 * distributed by any means, provided no charge is made for it.
 *
 * Matthew Chapman, csuoq@csv.warwick.ac.uk
 *    June 1995.
 */

/* lettround.c - computer solution of letters game and dictionary routines */

#include "xcountdown.h"
#include "globals.h"

#define TMP "/tmp/.OSPD"

#define pile_size 56
static int v_pile[pile_size],c_pile[pile_size];
static int v_pos,c_pos;

/* loads the dictionary into dict[] from {DICTIONARY}.gz - gzcats to /tmp */
void loaddict()
{
    FILE *fp;
    int count;
    int nextlen = 3;
    char sys[256],unname[256];
    Boolean is_gzipped=False;

    /* check for DICTIONARY then DICTIONARY.gz */
    fp = fopen(DICTIONARY,"r");
    if (fp==NULL)
    {
	/* try for .gz */
	sprintf(unname,"%s.gz",DICTIONARY);
	fp = fopen(unname,"r");
	if (fp!=NULL)
	{
	    is_gzipped=True;
	    fclose(fp);
	    /* generate tmp filename */
	    sprintf(unname,"%s%d",TMP,(int)getpid());
	    sprintf(sys,"gunzip -c %s.gz > %s",DICTIONARY,unname);
	    system(sys);
	    fp = fopen(unname,"r");
	}
    }

    if (fp==NULL)
    {
	fprintf(stderr,"Couldn't open dictionary from %s or %s.gz.\n",
		DICTIONARY,DICTIONARY);
        exit(1);
    }
    printf("Loading dictionary...\n");	
    count = 0;
    word_pos[0] = count;
    while (!feof(fp))
    {
	fscanf(fp, "%s\n",dict[count]);
	if (strlen(dict[count]) == nextlen)
	{
	    /* store word length boundaries - used for searching */
	    word_pos[nextlen-2] = count;
	    /* word length borders = word length - 2 */
	    nextlen++;
	}
	count++;
	if (count >= DICTSIZE)
	{
	    fprintf(stderr,"dictionary exceeds maximum size.\n");
	    exit(1);
	}
    }
    word_pos[nextlen-2] = count-1;
    fclose(fp);
    /* remove tmp file */
    if (is_gzipped)
	unlink(unname);
    printf("Done.\n");
}

/* performs binary search on dictionary for given word - returns True if found */
Boolean wordsearch(char *word)
{
    int start,end;
    int found = False;
    int compare;
    int lastmid = -1;
    int middle = -2;
    int wordlength=strlen(word);
	
    start=word_pos[wordlength-2];
    end=word_pos[wordlength-1];
    while ((lastmid != middle) && (!found))
    {
	lastmid = middle;
	middle = ((end - start)/2)+start;
	compare = strcmp(word,dict[middle]);
	if (!compare)
	    found = True;
	else
	    if (compare > 0)
		start = middle;
	    else
		end = middle;
    }
    return(found);
}

/* searches dictionary for decending length permutations of targ which are
   valid words, starting at given length. The longest valid permutation is
   returned. Used for letters game, and conundrum generation.
*/
char *search(char *targ,int start)
{
    int l,i,j;
    char tcpy[10];
    char *c;
    Boolean done;

    /* each word from the dictionary of the required length is checked to see
       if it can be formed from the target array of letters
       */		
    for (l=start; l>1; l--)
    {
	for (i=word_pos[l-2]; i<word_pos[l-1]; i++)
	{
	    strcpy(tcpy,targ);
	    done=False;
	    for (j=0; ((!done) && j<l); j++)
	    {
		c=strchr(tcpy,dict[i][j]);
		if (c==NULL)
		    done=True;
		else
		    *c=' ';	
	    }
	    /* first solution found is the longest, so return it */
	    if (!done)
		return(dict[i]);
	}
    }
    return("");
}

/* creates two piles for vowels and consonants with given distributions */
void InitPiles(void)
{
    static int v_distr[] = {12,17,12,10,5};
    static int c_distr[] = {2,2,4,2,3,2,1,1,4,2,6,2,1,6,4,6,2,2,1,2,1};
    int i,j,pos=0;

    /* set pointers to start of piles */
    v_pos=0;
    c_pos=0;
    /* put letters into piles in order */
    for (i=0; i<5; i++)
	for (j=0; j<v_distr[i]; j++)
	    v_pile[pos++]=i;
    pos=0;
    for (i=0; i<21; i++)
	for (j=0; j<c_distr[i]; j++)
	    c_pile[pos++]=i;
	
    /* shuffle piles */
    for (i=0; i<1000; i++)
	Swap(&v_pile[rand()%pile_size],&v_pile[rand()%pile_size]);
    for (i=0; i<10000; i++)
	Swap(&c_pile[rand()%pile_size],&c_pile[rand()%pile_size]);
}

/* take a vowel from the pile and return it */
char GiveVowel(void)
{
    static char letts[] = "AEIOU";
    assert(v_pos<pile_size);
    return(letts[v_pile[v_pos++]]);
}

/* take a consonant from the pile and return it */
char GiveConsonant(void)
{
    static char letts[] = "BCDFGHJKLMNPQRSTVWXYZ";
    assert(c_pos<pile_size);
    return(letts[c_pile[c_pos++]]);
}
