/*
 *
 * botutil3.c -- utilities for the robot, part 3
 *
 * 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 "proto.h"

char p1[20], p2[20];

void StartLookForBoard()
/* Initiate `board' command. */
{
    if( LookingForBoard == LFB_NONE ) {
	QueueCommand( "board", 0 );
	LookingForBoard = LFB_GENERAL;
	FoundBoard = 0;
    }
}

void StartResume()
/* Initiate `resume' command. */
{
    if( LookingForBoard == LFB_NONE || LookingForBoard == LFB_COMMIT ) {
/* LookingForBoard will be 3 when ACBot resumes when it was in the middle
   of committing. */
	if( LookingForBoard == LFB_NONE )
	    QueueCommand( "\"Resuming game...", 0 );
	QueueCommand( "board", 0 );
	LookingForBoard = LFB_RESUME;
	MyPlrNum = -1;
	TheirPlrNum = -1;
	FoundTurn = -1;
	FoundBoard = 0;
	InitBoard();
	InitTiles();
	InitGameStart();
    }
}

void StartHintCommand( name, form )
    char *name;
    char form;
/* Initiate `hint' command. */
{
    int i;
    char *p1;

    if( LookingForBoard == LFB_NONE ) {
	p1 = InRecH( "hint" ) + 4;
	while( *p1 == ' ' ) p1++;
	i = 0;
	while( *p1 != '"' && *p1 != ' ' && i < 20 ) LFBLoc[i++] = *p1++;
	LFBLoc[i] = '\0';
	sprintf( WriteBuf, "look %s\n", LFBLoc );
	QueueCommand( WriteBuf, 0 );
	LFBForm = form;
	LookingForBoard = LFB_COMMAND;
	strcpy( LFBName, name );
	LFBMaxTicks = CurrTicks + 10; /* Wait five seconds to find board. */
	MyPlrNum = -1;
	TheirPlrNum = -1;
	FoundTurn = -1;
	InitBoard();
	InitTiles();
    }
}

void DoBoardLookup()
/* Look for a move once the board and rack has been determined. */
{
    int i, j;
    compmove *tptr, *uptr;
    
    i = 1;
    WriteBuf[0] = LFBForm;
    AddToStr( LFBName, &i );
    AddToStr( " ", &i );
    ComputerMove( MyPlrNum );
    if( CHead == NULL ) {
	AddToStr( "I can't find a move, so I'd have to pass.", &i );
	TermStr( i, 0 );
    } else {
	if( CHead->placed > 0 ) {
	    CommentOnMyPlay( NULL, COMM_LOOK );
	} else if( CHead->placed < 0 ) {
	    AddToStr( "I would dump ", &i );
	    for( j = 0; j < -CHead->placed; j++ ) {
		WriteBuf[i++] = CHead->newlet[j].letter;
	    }
	    AddToStr( ".", &i );
	    TermStr( i, 0 );
	} else {
	    AddToStr( "I'd pass", &i );
	    AddToStr( ".", &i );
	    TermStr( i, 0 );
	}
	tptr = CHead;
	while( tptr != NULL ) {
	    uptr = tptr->next;
	    free( (compmove *) tptr );
	    tptr = uptr;
	}
    }
}

void LookForBoard()
/* Check the received queue for things that might be a board.  Once found,
   process it. */
{
    int i, r, c, tile, tpn;
    char tilec, tbuf[40], statstr[40], *p;
    
    if( LookingForBoard == LFB_LOG ) return;
    if( RecHead == NULL ) {
	if( LookingForBoard == LFB_COMMAND )
	    if( CurrTicks > LFBMaxTicks && FoundBoard == 0 ) {
		sprintf( WriteBuf, "%c%s `%s' doesn't look like a board to me.\n",
			 LFBForm, LFBName, LFBLoc );
		QueueCommand( WriteBuf, 2 );
		LookingForBoard = LFB_NONE;
	    }
	return;
    }
    while( RecHead != NULL ) {
	if( strcmp( RecHead->string, BOARDDELIM ) == 0 ) {
	    LPrint( "Found BOARDDELIM\n" ); 
	    if( FoundBoard == 1 ) {
		FoundBoard = 0;
		goto done_look_for_board;
	    } else {
		FoundBoard = 1;
	    }
	}
	if( FoundBoard == 0 ) goto lookrrs;
	
/* Determine rated/timed status */
	if( LookingForBoard != LFB_COMMAND ) {
	    if( InRecH( "are in effect." ) != NULL )
		TimedGame = TIMED_YES;
	    if( InRecH( "are not in effect." ) != NULL )
		TimedGame = TIMED_NO;
	    if( InRecH( "counts for ratings." ) != NULL
		|| InRecH( "counts for English ratings." ) != NULL
		|| InRecH( "counts for OSPD ratings." ) != NULL
		|| InRecH( "counts for SOWPODS ratings." ) != NULL )
		RatedGame = RATED_YES;
	    if( InRecH( "does not count for ratings." ) != NULL )
		RatedGame = RATED_NO;
	}
	
	p = RecHead->string;
	if( ( p[0] == ' ' || p[0] == '1' ) && ( p[1] >= '0' && p[1] <= '9' )
	    && p[2] == '|' ) {
/* Determine tiles already placed on board */
	    r = p[1] - '0';
	    if( p[0] == '1' ) r += 10;
	    for( i = 3; i <= 31; i += 2 ) {
		c = ( i - 1 ) / 2;
		if( p[i] == '\'' ) Board[r][c] = CH_DL;
		else if( p[i] == '"' ) Board[r][c] = CH_TL;
		else if( p[i] == '-' ) Board[r][c] = CH_DW;
		else if( p[i] == '=' ) Board[r][c] = CH_TW;
		else if( p[i] == ' ' || p[i] == '.' ) Board[r][c] = CH_EM;
		if( p[i] < 'A' ) continue;
		Board[r][c] = p[i];
		if( p[i] >= 'a' ) {
		    Board[r][c] = p[i] - 'a' + 'A';
		    tile = 26;
		    if( B1X == -1 ) {
			B1X = c;
			B1Y = r;
		    } else {
			B2X = c;
			B2Y = r;
		    }
		}
		else tile = p[i] - 'A';
		TilesLeft[tile]--;
	    }
	    
	    if( LookingForBoard == LFB_GENERAL ) goto lookrrs;

/* Find tiles on racks */	
	    if( r == 2 ) {
		p = RecHead->string + 38;
		i = 0;
		while( *p != ' ' ) p1[i++] = *p++;
		p1[i] = '\0';
	    } else if( r == 3 ) {
		p = RecHead->string + 38;
		i = 0;
		while( *p != ' ' ) p2[i++] = *p++;
		p2[i] = '\0';
/* Kludge for `hint' command: set FoundTurn to -2 if more than two
   players on a board.  Set to -3 for no game on board. */
	    } else if( r == 4 && RecHead->string[38] != '\n' ) {
		if( RecHead->string[35] == '\n' )
		    FoundTurn = -3;
		else
		    FoundTurn = -2;
	    }
	    if( r == 2 || r == 3 ) {
		tpn = r - 2;
		if( LookingForBoard != LFB_COMMAND ) {
		    if( r == 2 ) {
			tpn = 0;
			if( strcmp( p1, PlrName ) == 0 ) {
			    MyPlrNum = 0;
			    JoinOrder = JOIN_ME_FIRST;
			}
			if( strcmp( p1, Opponent ) == 0 ) TheirPlrNum = 0;
		    } else if( r == 3 ) {
			tpn = 1;
			if( strcmp( p2, PlrName ) == 0 ) {
			    MyPlrNum = 1;
			    JoinOrder = JOIN_THEM_FIRST;
			}
			if( strcmp( p2, Opponent ) == 0 ) TheirPlrNum = 1;
		    }
		}
		for( i = 0; i < 7; i++ ) PlrTiles[tpn][i] = 0;
		while( *p == ' ' ) p++;
		for( i = 0; *p != ' '; ) {
		    tilec = *p++;
		    if( tilec != '-' ) PlrTiles[tpn][i++] = tilec;
		}
		SortTiles( PlrTiles[tpn] );
		while( *p == ' ' ) p++;
		for( PlrScores[tpn] = 0; *p >= '0' && *p <= '9'; )
		    PlrScores[tpn] = PlrScores[tpn] * 10 + *p++ - '0';
	    }
	}

/* Handle special cases for 'resume' Command.  A bit kludgey. */
	if( LookingForBoard == LFB_RESUME ) {
	    sprintf( statstr, "%s to commit.", PlrName );
	    if( InRecH( statstr ) != NULL )
		LookingForBoard = LFB_COMMIT;
	    sprintf( statstr, "%s to end the game.", PlrName );
	    if( InRecH( statstr ) != NULL )
		LookingForBoard = LFB_END;
	    sprintf( statstr, "%s to play.", PlrName );
	    if( InRecH( statstr ) != NULL ) FoundTurn = MY_MOVE_F;
	    sprintf( tbuf, "%s to play.", Opponent );
	    if( InRecH( tbuf ) != NULL ) FoundTurn = THEIR_MOVE;
	    sprintf( tbuf, "%s to commit.", Opponent );
	    if( InRecH( tbuf ) != NULL ) FoundTurn = THEIR_COMMIT;
	    sprintf( tbuf, "%s to end the game.", Opponent );
	    if( InRecH( tbuf ) != NULL ) FoundTurn = THEIR_END;
	} else if( LookingForBoard == LFB_COMMAND ) {
	    sprintf( tbuf, "%s to play.", p1 );
/* FoundTurn will be -2 if the game has more than two players. */
	    if( InRecH( tbuf ) != NULL && FoundTurn != -2 ) {
		FoundTurn = MY_MOVE_F;
		MyPlrNum = 0;
		TheirPlrNum = 1;
	    }
	    sprintf( tbuf, "%s to play.", p2 );
	    if( InRecH( tbuf ) != NULL && FoundTurn != -2 ) {
		FoundTurn = MY_MOVE_F;
		MyPlrNum = 1;
		TheirPlrNum = 0;
	    }
	}
	
      lookrrs:
	RemoveReceivedString();
    }
    return;
    
  done_look_for_board:
    if( LookingForBoard == LFB_COMMIT ) { /* ACBot was supposed to commit. */
	QueueCommand( "\"Committing and resuming again...", 0 );
	QueueCommand( "commit", 0 );
	StartResume();
	RemoveReceivedString(); /* Remove BOARDDELIM string. */
	return; /* Return immediately. */
    } else if( LookingForBoard == LFB_END ) {
	MeEndGame(); /* ACBot was supposed to end the game. */
	goto end_look_for_board;
    }
    
    if( LookingForBoard == LFB_RESUME ) {
	if( MyPlrNum == -1 || TheirPlrNum == -1 ) {
	    SayToOpp( "This game isn't between you and me." );
	    GoHome();
	    goto end_look_for_board;
	} else if( FoundTurn == THEIR_COMMIT ) {
	    SayToOpp( "Please `commit' your move and try again." );
	    GoHome();
	    goto end_look_for_board;
	} else if( FoundTurn != MY_MOVE_F && FoundTurn != THEIR_MOVE
	    && FoundTurn != THEIR_END ) {
	    SayToOpp( "`resume' failed -- can't find whose turn it is." );
	    GoHome();
	    goto end_look_for_board;
	}
    } else if( LookingForBoard == LFB_COMMAND ) {
	if( strcmp( p1, LFBName ) == 0 || strcmp( p2, LFBName ) == 0 ) {
	    sprintf( WriteBuf, "%c%s You can't use `hint' on a board where you're a player.\n", LFBForm, LFBName );
	    QueueCommand( WriteBuf, 2 );
	    goto end_look_for_board;
	}
	if( strcmp( p1, PlrName ) == 0 || strcmp( p2, PlrName ) == 0 ) {
	    sprintf( WriteBuf, "%c%s You can't use `hint' on a board where I'm a player.\n", LFBForm, LFBName );
	    QueueCommand( WriteBuf, 2 );
	    goto end_look_for_board;
	}
	if( FoundTurn == -1 ) {
	    sprintf( WriteBuf, "%c%s I can't find whose move it is on `%s'.\n", LFBForm, LFBName, LFBLoc );
	    QueueCommand( WriteBuf, 2 );
	    goto end_look_for_board;
	} else if( FoundTurn == -2 ) {
	    sprintf( WriteBuf, "%c%s `%s' doesn't have two players on it.\n", LFBForm, LFBName, LFBLoc );
	    QueueCommand( WriteBuf, 2 );
	    goto end_look_for_board;
	} else if( FoundTurn == -3 ) {
	    sprintf( WriteBuf, "%c%s `%s' has no game in progress on it.\n", LFBForm, LFBName, LFBLoc );
	    QueueCommand( WriteBuf, 2 );
	    goto end_look_for_board;
	} else if( MyPlrNum == 0 ) {
	    sprintf( WriteBuf, "%c%s Finding %s's best move on `%s'...\n", LFBForm, LFBName, p1, LFBLoc );
	    QueueCommand( WriteBuf, 2 );
	} else if( MyPlrNum == 1 ) {
	    sprintf( WriteBuf, "%c%s Finding %s's best move on `%s'...\n", LFBForm, LFBName, p2, LFBLoc );
	    QueueCommand( WriteBuf, 2 );
	}
    }
    
    if( LookingForBoard == LFB_GENERAL || LookingForBoard == LFB_RESUME ) {
	if( RatedGame == RATED_YES ) {
	    QueueCommand( "o rated y", 0 );
	} else if( RatedGame == RATED_NO ) {
	    QueueCommand( "o rated n", 0 );
	}
	if( TimedGame == TIMED_YES ) {
	    QueueCommand( "o timed y", 0 );
	} else if( TimedGame == TIMED_NO ) {
	    QueueCommand( "o timed n", 0 );
	}
	if( RatedGame != RATED_NONE && TimedGame != TIMED_NONE ) {
	    i = 0;
	    AddToStr( "\"This game is ", &i );
	    if( RatedGame == RATED_YES && TimedGame == TIMED_YES ) {
		AddToStr( "rated and timed.", &i );
	    } else if( RatedGame == RATED_NO && TimedGame == TIMED_YES ) {
		AddToStr( "timed but not rated.", &i );
	    } else if( RatedGame == RATED_YES && TimedGame == TIMED_NO ) {
		AddToStr( "rated but not timed.", &i );
	    } else if( RatedGame == RATED_NO && TimedGame == TIMED_NO ) {
		AddToStr( "neither rated nor timed.", &i );
	    }
	}
	TermStr( i, 0 );
    }
    
    if( LookingForBoard == LFB_RESUME ) {
	CalcHooks();
	if( FoundTurn == MY_MOVE_F ) {
	    FoundRack = 1;
	    SayToOpp( "It is my turn." );
	    LookingForBoard = LFB_LOG;
	    AddTagEntry( TTYPE_LOG, NULL, Opponent, "", ' ' );
	    sprintf( WriteBuf, "log -tagged" );
	    QueueCommand( WriteBuf, 0 );
/*	    ChangeState( MY_MOVE_F ); */
	} else if( FoundTurn == THEIR_MOVE ) {
	    FoundRack = 1;
	    SayToOpp( "It is your turn." );
	    ChangeState( THEIR_MOVE );
	} else if( FoundTurn == THEIR_END ) {
	    SayToOpp( "You must type `end' to end the game." );
	    WhoEndsGame = THEY_END_GAME;
	    ChangeState( END_OF_GAME );
	}
    } else if( LookingForBoard == LFB_COMMAND ) {
	CalcHooks();
	sprintf( WriteBuf, "%s BOARD_LOOKUP", LFBName );
	QueueCommand( WriteBuf, 0 );
    }
    
  end_look_for_board:
    if( LookingForBoard != LFB_LOG ) LookingForBoard = LFB_NONE;
    RemoveReceivedString();
    return;
}

void ClearLFB()
/* Clear LookingForBoard flag after an LFB_LOG. */
{
    LookingForBoard = LFB_NONE;
}

