#include <Vio.h>
#include "checkers.h"

/*
 * dcheckers [-r <NoOfHosts>]
 *
 *
 * dcheckers is the distributed version of the checkers program.
 * dcheckers.c's (main()'s) role is that of the master. remchecker.c's
 * represents the slaves. Most of the checker routines could be employed
 * without change. The idea behind the distribution is to have slaves
 * execute some of the recursive calls to tree(). The top of the 
 * alpha-beta search tree is represented by the procedures treetop1()
 * and treetop2(). treetop2() sends calls to the slaves one recursion level
 * deeper than treetop1(). A finer grade of partitioning is therefore
 * achieved with treetop2().
 *
 * New files needed for the distributed version are
 *   dcheckers.c	evolved from checkers.c
 *   remcheckers.c	evolved from tree.c
 *   treetop1.c		evolved from tree.c
 *   treetop2.c		evolved from tree.c
 *
 * The following files were slightly modified for the distributed version:
 *   generate1.c:  Creates the next move, returning -1 if no further move
 *		   is posible. The new board is only generated, however, if
 *		   requested by a non-null newb pointer.
 *   tree4.c:      Instead of passing the alpha-beta values as parameters
 *		   with each recursive call, an external array: abarray is
 *		   maintained. One element in the array for each recursive
 *		   level. A search can be started with a tighter a-b window,
 *		   if the a-b values of the higher levels are known.
 *		   This is made possible by this array.
 */


char	sillycomment[100] ;
unsigned long Idlecounter ;
int verbose ;
int RootStackSize = 6000 ;

main( argc, argv ) int argc; char **argv;

    /* This is the driving routine for the checkers program. */

  {
    extern int   Board[], PrevBoard[], Value, PrevValue, Depth;

    int         *bestb, *oldb, s, rflag;
    int		s1, s2, t1, t2 ;	/* just for timing */
    ProcessId	startup() ;

    /* check flags to see if a distributed version should run */
    rflag = 0 ;
    verbose = 0 ;
    while (--argc > 0) {
        argv++ ;
	if(argv[0][0] == '-') 
	    switch(argv[0][1]) {
		case 'r':
				rflag++;
				++argv;
				--argc ;
		        	sscanf (*argv, "%d", &NoOfTeams) ;
				if (NoOfTeams>MAXSLAVES) 
				    NoOfTeams = MAXSLAVES ;
				break ;
		case 'v':	
				verbose++ ;
				break ;

		default:
				printf("Unknown flag %s\n", *argv) ;
				break;
	    }
      }
   
    if (rflag)
        startupremoteteams() ;

    bestb = (int *) calloc( sizeof(int), 64 );
    oldb = (int *) calloc( sizeof(int), 64 );

	/*
	 * Set up the VGT for the checker board.
	 * The user will be prompted (by the VGTS view manager) for the
	 * location of the view containing the checker board, and the
	 * initial board configuration will be displayed.
	 */
    SetupVGT();

    /* Display the board (initial configuration). */
    FullDisplay(Board, TRUE);

    /* Print a 'welcoming message'. */
    if (rflag) sprintf(sillycomment, 
     "Welcome to distributed V checkers (%d slaves)", NoOfHosts) ;
    else sprintf(sillycomment, "Welcome to V checkers.") ;
    Silly_Comment(sillycomment  );


    /* Copy the (initial) board into PrevBoard, in case the first thing that
     * the human does is request to back up a move. */
    Copy(PrevBoard, Board, 64*BYTES_PER_WORD);
    PrevValue = Value;

    /* Do the following until the game is over: */

    while(1)
      {
        /* Prompt for the human's move. */
        Prompt("It's your move.");

	/* Get the human's next move. */
        Player_move();

       /* The computer resigns if there are no more black pieces on the board.
 	*/
        if( No_man( BC, BK ) )
            EndGame( "  You win!" );

	/* Let the user know that the computer is calculating its move. */
	Prompt("...thinking...");

	/* Save a copy of the current board. */
	Copy( oldb, Board, 64*BYTES_PER_WORD );

       /* Determine the computer's move and display the altered board which
        * reflects it.
	*/

	Idlecounter = 0 ;

	s1 = GetTime(&t1) ;
	/* Computer makes its move. */
	if (rflag)
            Value = FinePartitioningTreetop(Board, bestb, 0, -INFINITY );
	else
	    Value = Tree( Board, bestb, 0, -INFINITY );
	ComputeTime(s1,t1,s2,t2) ;

	if (verbose) printf(" %d secs and %d ticks idlecount=%d value = %d\n", 
		s2, t2, Idlecounter, Value) ;

	/* If the machine couldn't make a move, then "Value" will be INFINITY.
	 * (In situations where a loss is known, but a computer move was
	 * possible, "Value" will be slightly greater than INFINITY, because
	 * in such a case the computer will find itself stymied until a lower
	 * level.)
	 */
	if (Value == INFINITY)
 	    EndGame( "  You win!" );

	Copy( Board, bestb, 64*BYTES_PER_WORD );

       /*
	* Redisplay the squares which the computer has changed,
        */
	for (s = 7; s < 56; ++s)
	    if (Board[s] != oldb[s])
		UpdateDisplayedSquare(s, FALSE);
	UpdateValueIndicator();

	/*
        * The computer wins if there are no more red pieces for the human
        * to move.
	*/
        if( No_man( RC, RK ) )
            EndGame( "  You lose." );
	/*
        * Print a commentary on the play, based on the amount of change
        * in the board valuation between moves by the human.
	*/
        if( Value < (-INFINITY + 100) )
            Silly_Comment( "You should resign." );
        else if( Value < -500 )
            Silly_Comment( "Consider resigning?" );
        else if( (Value-PrevValue) > 200 )
            Silly_Comment( "You're better than I thought" );
        else if( (Value-PrevValue) > 100 )
            Silly_Comment( "Well done" );
        else if( (PrevValue-Value) > 200 )
            Silly_Comment( "Fell for it didn't you" );
        else if( (PrevValue-Value) > 100 )
            Silly_Comment( "Thanks" );
	else
	    Silly_Comment(0);

      }
  }

#define MAXSLAVES 20
#define MAXARGS 5
#define INIT_REQUESTCODE 0
struct slaves Slaves[MAXSLAVES] ;
ProcessId Swatch ;
char *SlaveArgs[MAXARGS] ;


startupremoteteams()
  {
    extern int Depth ;
    extern ProcessId Group ;
    char *args[2] ;
    Message msg ;
    struct rMsg *rmsg = (struct rMsg *) msg ;
    int noOfHosts, i ;
    int initMsg(),  slavewatch(), noOfSlaves ;
    extern int recreateSubtask();
    noOfSlaves = NoOfTeams ;

    /* setup argv array */
    SlaveArgs[0] = REMFILE ;
#ifdef VERBOSE
    SlaveArgs[0] = VREMFILE ;
#endif
#ifdef DEBUG
    SlaveArgs[0] = DREMFILE ;
#endif
    SlaveArgs[1] = NULL  ;

#ifdef GROUPSEND
    Group = CreateGroup(0,0) ;
    if (Group == 0)
      {
        Group = 0x12351234 ;
	printf("I guess I'll create my own group in that case: %x\n",Group) ;
      }
    /* LeaveGroup(Group,0) ; */
#else
    Group = 0 ;
#endif

    NoOfHosts = startupSlaves( Slaves, noOfSlaves, SlaveArgs, initMsg ) ;
    for( i=0; i<NoOfHosts; i++)
        Slaves[i].recreateSubtask = recreateSubtask ;

    Swatch = Create( 0, slavewatch, 1024 ) ;
    Ready( Swatch, 3, Slaves, NoOfHosts, /*restart*/ 1 ) ;
  }

initMsg( msg, slave, master )
    struct initMsg *msg ;
    int slave ;
    ProcessId master ;
  {
    msg->requestcode = INIT_REQUESTCODE ;
    msg->slave = slave ;
    msg->master = master ;
    msg->memsize = Depth ;
    msg->segptr = (char *) Group ;
    msg->segsize = 0;
    if( Slaves[slave].computing )
        msg->recreating = 1 ;
    else
        msg->recreating = 0 ;
    return ;
  }


EndGame(s)
    char s[];
    /* Prints the string "s" as a prompt, then quits. */
  {
    Prompt(s);
    Delay(1, 0);
    Quit();
  }
    

