/*
 *
 * misc.c -- miscellaneous routines
 *
 * This code is copyright 1995 by James A. Cherry, jac@doe.carleton.ca.
 * It is not to be redistributed or modified without his permission.
 *
 */

#include "funddefs.h"
#include "globals.h"
#include "socket.h"
#include "botutil.h"
#include "fowc.h"
#include "proto.h"

char spaces[81] =
"                                        \
                                        ";

void ExitWindow()
/* Tear down stuff for exit from program. */
{
    fclose( LogFile );
    if( SockP != -1 ) close( SockP );
	exit( 2 );
}

void InitBoard()
/* Initialize board and related data structures. */
{
    int i, j;
    
    for( i = 1; i < 16; i++ ) {
	for( j = 1; j < 16; j++ ) {
	    Board[i][j] = CH_EM;
	    HHook[i][j][26] = -1;
	    VHook[i][j][26] = -1;
	}
    }
    Board[1][1] = CH_TW;
    Board[8][1] = CH_TW;
    Board[8][8] = CH_DW;
    for( i = 2; i < 6; i++ ) {
	Board[i][i] = CH_DW;
    }
    Board[2][6] = CH_TL;
    Board[6][2] = CH_TL;
    Board[6][6] = CH_TL;
    Board[1][4] = CH_DL;
    Board[4][1] = CH_DL;
    Board[3][7] = CH_DL;
    Board[7][3] = CH_DL;
    Board[8][4] = CH_DL;
    Board[7][7] = CH_DL;
    for( i = 1; i < 9; i++ )
	for( j = 1; j < 8; j++ ) {
	    Board[16-j][i] = Board[i][j];
	    Board[16-i][16-j] = Board[i][j];
	    Board[j][16-i] = Board[i][j];
	}
}

void InitTiles()
/* Initialize tiles in bag. */
{
    int i, j;
    
    for( i = 0; i < 27; i++ )
	TilesLeft[i] = Letters[i].tiles;
    for( i = 0; i < 4; i++ )
	for( j = 0; j < 7; j++ )
	    PlrTiles[i][j] = 0;
    B1X = 0;
    B2X = 0;
    B1Y = 0;
    B2Y = 0;
}

void InitStuff()
/* Set up stuff for ACBot startup. */
{
    SockP = -1;
    RBIn = ReadBuf; RBLast = RBIn + RBUF_SIZE - 3;
    RecHead = NULL;
    TagHead = NULL;
    Opponent[0] = '\0';
    NameArg[0] = '\0';
    PrevState = START_STATE;
    CurrState = START_STATE;
    PrevTicks = 0;
    CurrTicks = 0;
    MWXSize = 71 - strlen( PlrName );
    MWYSize = 8;
    SType = WORDS_ROBOT;
    LineList = NULL;
    FileCount = 0;
    VerticalPlay = 0;
    
    seed_random();
    signal( SIGINT, ExitWindow );
    signal( SIGHUP, ExitWindow );
    signal( SIGQUIT, ExitWindow );
}

void new_leave_values()
/* New leave values for DDBot. */
{
    RackLeave[ 2][1] =   1; RackLeave[ 2][2] =  -7;
    RackLeave[ 6][1] =  -2; RackLeave[ 6][2] = -11;
    RackLeave[ 7][1] =   2; RackLeave[ 7][2] =  -4;
    RackLeave[10][1] =  -3;
    RackLeave[14][1] =  -2; RackLeave[14][2] = -12;
    RackLeave[14][3] = -30; RackLeave[14][4] = -56;
    RackLeave[14][5] = -90; RackLeave[14][6] =-132;
    RackLeave[15][1] =  -2; RackLeave[15][2] = -10;
    RackLeave[16][1] = -12;
    RackLeave[20][1] =  -5; RackLeave[20][2] = -17;
    RackLeave[20][3] = -36; RackLeave[20][4] = -62;
    RackLeave[24][1] =  -2; RackLeave[24][2] = -15;
    RackLeave[25][1] =   6;
}

void ReadWords()
/* Read dictionary. */
{
    FILE *fp;
    char inp[MAX_WLEN + 1], tinp[MAX_WLEN + 1];
    int i, j, tlen, rlen;
    long pt, wr;

    if( DoomName == DDDOOM ) {
	fp = fopen( "dddict", "r" );
	new_leave_values();
    } else {
	fp = fopen( "acdict", "r" );
    }
    if( fp == NULL ) {
	ExitWindow();
	exit( 13 );
    }
    pt = 0;
    wr = 0;
    for( i = 0; i < MAX_WLEN + 2; i++ )
	for( j = 0; j < 27; j++ )
	    WLen[i][j] = -1;
    tlen = 2;
    WLen[tlen][0] = wr;
    tinp[0] = '\0';
    while( fscanf( fp, "%s", inp ) != EOF ) {
	rlen = strlen( inp );
	if( rlen < 2 || rlen > MAX_WLEN ) {
	    ExitWindow();
	    exit( 14 );
	}
	if( rlen < strlen( tinp ) ||
	    ( strcmp( tinp, inp ) > 0 && strlen( tinp ) == rlen ) ) {
	    ExitWindow();
	    exit( 15 );
	}
	for( i = 0; i < rlen; i++ ) {
	    if( inp[i] >= 'a' && inp[i] <= 'z' ) inp[i] = inp[i] - 'a' + 'A';
	    else if( inp[i] < 'A' || inp[i] > 'Z' ) {
		ExitWindow();
		exit( 16 );
	    }
	}
	if( rlen > tlen ) {
	    for( i = tlen + 1; i <= rlen; i++ ) WLen[i][0] = wr;
	    tlen = rlen;
	} else if( inp[0] != tinp[0] ) {
	    WLen[rlen][inp[0] - 'A'] = wr;
	}
	strcpy( &Words[pt], inp );
	WPtr[wr++] = pt;
	pt += rlen + 1;
	strcpy( tinp, inp );
    }
    Words[pt] = '\0';
    WPtr[wr] = pt;
    DictSize = pt;
    for( i = tlen + 1; i < MAX_WLEN + 2; i++ ) WLen[i][0] = wr;
    for( i = 1; i < MAX_WLEN + 1; i++ ) {
	if( WLen[i][25] == -1 )
	    WLen[i][25] = WLen[i + 1][0];
	for( j = 24; j >= 0; j-- )
	    if( WLen[i][j] == -1 )
		WLen[i][j] = WLen[i][j + 1];
	WLen[i][26] = WLen[i + 1][0];
    }
    fclose( fp );
}

void ReadBlacklist()
/* Read blacklist. */
{
    FILE *fp;
    int i;
    
    i = 0;
    fp = fopen( "blacklist", "r" );
    while( fscanf( fp, "%s", BlackList[i] ) != EOF ) i++;
    fclose( fp );
    BListLen = i;
}

void ConvertMove( mvptr )
    compmove *mvptr;
/* Change move from internal format to `8b RETINAS' format. */
{
    int i, x, y, dir, placed;
    int dx, dy, cl, cw, bad;
    
    MoveString[0] = '\0';
    MoveLS[0] = '\0';
    MoveWS[0] = '\0';
    if( mvptr == NULL ) return;
    placed = mvptr->placed;
    if( placed < 0 ) {
	strcpy( MoveString, "xch " );
	strcpy( MoveLS, "xch" );
	for( i = 0; i < -placed; i++ ) {
	    MoveString[4 + i] = mvptr->newlet[i].letter;
	    MoveWS[i] = mvptr->newlet[i].letter;
	}
	MoveString[4 + i] = '\0';
	MoveWS[i] = '\0';
	return;
    } else if( placed == 0 ) {
	strcpy( MoveString, "    pass" );
	strcpy( MoveWS, "pass" );
	MoveLS[0] = '\0';
	return;
    }
    x = mvptr->newlet[0].x;
    y = mvptr->newlet[0].y;
    dir = mvptr->dir;
    dx = 1 - dir;
    dy = dir;
/* Hack for single tile placed */
    if( placed == 1 ) {
	LPrint( "One tile placed.\n" ); 
	bad = 0;
	if( x + dx < 16 && y + dy < 16 ) {
	    if( Board[y + dy][x + dx] < 'A' ) bad++;
	} else bad++;
	if( x - dx > 0 && y - dy > 0 ) {
	    if( Board[y - dy][x - dx] < 'A' ) bad++;
	} else bad++;
	if( bad == 2 ) {
	    LPrint( "Must switch directions.\n" ); 
	    mvptr->dir = 1 - dir;
	    dir = mvptr->dir;
	    dx = 1 - dir;
	    dy = dir;
	}
    }
    while( x - dx > 0 && y - dy > 0 ) {
	if( Board[y - dy][x - dx] >= 'A' ) {
	    x -= dx;
	    y -= dy;
	} else break;
    }
    if( dir == 0 ) {
	sprintf( MoveString, "%2d%c ", y, x + 'a' - 1 );
	sprintf( MoveLS, "%d%c", y, x + 'a' - 1 );
    } else {
	sprintf( MoveString, "%c%-2d ", x + 'a' - 1, y );
	sprintf( MoveLS, "%c%d", x + 'a' - 1, y );
    }
    cl = 4;
    cw = 0;
    for( i = 0; i < placed || Board[y][x] >= 'A'; ) {
	if( Board[y][x] >= 'A' ) {
	    MoveString[cl++] = Board[y][x];
	    MoveWS[cw++] = Board[y][x];
	} else {
	    if( mvptr->newlet[i].letter == CH_BL ) {
		MoveString[cl++] = mvptr->newlet[i].blankchar - 'A' + 'a';
		MoveWS[cw++] = mvptr->newlet[i].blankchar - 'A' + 'a';
	    } else {
		MoveString[cl++] = mvptr->newlet[i].letter;
		MoveWS[cw++] = mvptr->newlet[i].letter;
	    }
	    i++;
	}
	x += dx;
	y += dy;
	if( x > 15 || y > 15 ) break;
    }
    MoveString[cl] = '\0';
    MoveWS[cw] = '\0';
}

void MyToUpper( string )
  char *string;
/* Convert string to upper case. */
{
    char *p;

    p = string;
    while( *p != '\0' ) {
	if( *p >= 'a' && *p <= 'z' ) *p = *p - 'a' + 'A';
	p++;
    }
}

void SortTiles( rack )
    char *rack;
/* Sort tiles pointed to by `rack'. */
{
    int i, j;
    char t;
    
    for( i = 0; i < 7 && rack[i] != '\0'; i++ );
    for( ; i < 7; rack[i] = '\0', i++ );
    for( i = 5; i >= 0; i-- ) {
	for( j = 0; j <= i; j++ ) {
	    if( ( ( rack[j] >= 'A' && rack[j] <= 'Z' )
		  || rack[j] == CH_BL ) &&
		( ( rack[j + 1] >= 'A' && rack[j + 1] <= 'Z' )
		  || rack[j + 1] == CH_BL ) &&
		rack[j] > rack[j + 1] ) {
		t = rack[j];
		rack[j] = rack[j + 1];
		rack[j + 1] = t;
	    }
	}
    }
    CompressRack( rack );
    LPrint( "(Rack is now:" );
    for( i = 0; i < 7; i++ ) LPrint( " %2d", rack[i] );
    LPrint( ")\n" ); 
}

void CompressRack( rack )
    char *rack;
/* Remove empty spaces from a rack and pack the letters together. */
{
    int i, j;

    for( i = 0, j = 0; i < 7; i++ ) {
	if( rack[i] == '\0' ) j++;
	else rack[i - j] = rack[i];
    }
    for( i = 7 - j; i < 7; i++ ) rack[i] = '\0';
}

int Let2Ind( let )
    char let;
/* Convert A-Z and ? to 0-25 and 26, 27 for unknown tile. */
{
    if( let == CH_BL ) return( 26 );
    if( let >= 'A' && let <= 'Z' ) return( let - 'A' );
    if( let >= 'a' && let <= 'z' ) return( let - 'a' );
    return( 27 );
}

char Ind2Let( ind )
    int ind;
/* Convert index 0-27 to A-Z, ?, and -. */
{
    if( ind == 27 ) return( CH_UN );
    return( ind == 26 ? CH_BL : ind + 'A' );
}

void AddToStr( string, index )
  char *string;
  int *index;
/* Add a string to WriteBuf. */
{
    sprintf( &(WriteBuf[*index]), "%s", string );
    *index += strlen( string );
}

void TermStr( index, delay )
  int index, delay;
/* Terminate WriteBuf string and queue it. */
{
    WriteBuf[index] = '\n';
    QueueCommand( WriteBuf, delay );
}

void seed_random()
/* Seed the random number generator. */
{
    long now, time();
    
    now = time( 0 );
    srandom( now % 65536 - 32768 );
}

long GetRandom()
/* Pick a random number. */
{
    return( (long) random() );
}

