// ComputerPlayer.m
// Project: Cribbage
// Stephan Wacker
// 93-09-16


#import "deck.h"
#import "cribbage.h"

#import "ComputerPlayer.h"
#import "Deck.h"
#import "ScoreBoard.h"


@implementation ComputerPlayer


- (char *) pronoun
{
    return "I";
}

- (char *) possessivePronoun
{
    return "my";
}

- (char *) reflexivePronoun
{
    return "me";
}


- (int) selectCardForBestScore
//
// Return index of card to play for best score.
// Return -1 if no card scores.
//
{
    int		i, j, k, l;
    
    j = -1;
    k = 0;
    for (i = 0; i < FULLHAND; i++) {	/* maximize score */
	if( face[i] != FACE_NONE ) {
	    l = [table score: hand[i]];
	    if (l > k) {
		k = l;
		j = i;
	    }
	}
    }
    
    return j;
}


- (int) findVal: (int) v
{
    int		i;
    
    for( i = 0; i < FULLHAND; i++ )  {
	if( face[i] != FACE_NONE ) {
	    if(  VAL( hand[i].rank )  ==  v  )
		return( i );
	}
    }
    return( -1 );
}


- (int) numOfVal: (int) v
{
    int		i, j;
    
    for( i = 0, j = 0; i < FULLHAND; i++ )  {
	if( face[i] != FACE_NONE ) {
	    if(  VAL( hand[i].rank )  ==  v  )
		++ j;
	}
    }
    return( j );
}


- (int) selectCardNonscoring
{
    int		i, j, l;
    int		s = [table sumPlayed];

#define		NTV		10		/* number scores to test */

    /* score to test reachability of, and order to test them in */
    static	int	tv[ NTV ] = { 8, 7, 9, 6, 11, 12, 13, 14, 10, 5 };


    if(  s < 4  )  {		/* try for good value */
	if(  ( j = [self findVal: 4-s] ) >= 0  )
	    return( j );
	if(  ( j = [self findVal: 3-s] ) >= 0  &&  s == 0  )
	    return( j );
    }
    
    if(  s > 0  &&  s < 20  )  {
	for( i = 1; i <= 10; i++ )  {	/* try for retaliation to 31 */
	    if(  ( j = [self findVal: 21-i-s] )  >=  0  )  {
		if(  ( l = [self numOfVal: i] )  >  0  )  {
		    if(  l > 1  ||  VAL( hand[j].rank ) != i  )
			return( j );
		}
	    }
	}
    }
    
    if(  s < 15  )  {
	for( i = 0; i < NTV; i++ )  {	/* for retaliation after 15 */
	    if(  ( j = [self findVal: tv[i]-s] )  >=  0  )  {
		if(  ( l = [self numOfVal: 15-tv[i]] )  >  0  )  {
		    if(  l > 1  ||  VAL( hand[j].rank ) != 15-tv[i]  )
			return( j );
		}
	    }
	}
    }
    
    j = -1;
    for( i = FULLHAND-1; i >= 0; --i )  {	/* remember: h is sorted */
	if( face[i] != FACE_NONE ) {
	    l = s + VAL( hand[i].rank );
	    if(  l > 31  )  continue;
	    if(  l != 5  &&  l != 10  &&  l != 21  )  {
		j = i;
		break;
	    }
	}
    }
    if(  j >= 0  )  return( j );
    
    for( i = FULLHAND-1; i >= 0; --i )  {
	if( face[i] != FACE_NONE ) {
	    l = s + VAL( hand[i].rank );
	    if(  l > 31  )  continue;
	    if(  j < 0  )  j = i;
	    if(  l != 5  &&  l != 21  )  {
		j = i;
		break;
	    }
	}
    }
    return( j );
}


- (int) selectCard
//
// Return index of card to be played next.
//
{
    int		result;
    
    result = [self selectCardForBestScore];
    if (result < 0)				/* if nothing scores */
	result = [self selectCardNonscoring];
    
    return result;
}


- playOneCard
{
    if( [self canPlay] ) {
	[self playCardAt: [self selectCard]];
    } else {
	[self go];
    }
    
    return self;
}


- emptyHand
{
    [super emptyHand];
    knownum = 0;
    return self;
}


- chooseDiscard
{
    CARD		d[ CARDS ],  h[ FULLHAND ],  cb[ 2 ];
    register  int	i, j, k;
    int			nc, ns;
    long		sums[ 15 ];
    static  int		undo1[15]   = {0,0,0,0,0,1,1,1,1,2,2,2,3,3,4};
    static  int		undo2[15]   = {1,2,3,4,5,2,3,4,5,3,4,5,4,5,5};

    makedeck( d );
    nc = CARDS;
    for( i = 0; i < knownum; i++ )  {	/* get all other cards */
	remove_card( known[i], d, nc-- );
    }
    for( i = 0; i < 15; i++ )  sums[i] = 0L;
    ns = 0;
    for( i = 0; i < (FULLHAND - 1); i++ )  {
	cb[0] = hand[i];
	for( j = i + 1; j < FULLHAND; j++ )  {
	    cb[1] = hand[j];
	    for( k = 0; k < FULLHAND; k++ )  h[k] = hand[k];
	    remove_card( hand[i], h, FULLHAND );
	    remove_card( hand[j], h, FULLHAND - 1 );
	    for( k = 0; k < nc; k++ )  {
		sums[ns] += scorehand( h, d[k], CINHAND, TRUE, FALSE );
		if( [deck isCompCrib] )  sums[ns] += adjust( cb, d[k] );
		else	  sums[ns] -= adjust( cb, d[k] );
	    }
	    ++ns;
	}
    }
    j = 0;
    for( i = 1; i < 15; i++ )  if(  sums[i] > sums[j]  )  j = i;
    for( k = 0; k < FULLHAND; k++ )  h[k] = hand[k];
    remove_card( h[ undo1[j] ], hand, FULLHAND );
    remove_card( h[ undo2[j] ], hand, FULLHAND - 1 );
    hand[4] = h[ undo1[j] ];
    hand[5] = h[ undo2[j] ];
    
    return self;
}


- discard
{
    int		i;
    CARD	card;
    
    [self chooseDiscard];		/* puts best discard at end */
    
    for( i = CINHAND; i < FULLHAND; i++ ) {
	card = hand[i];
	face[i] = FACE_NONE;
	hand[i].rank = hand[i].suit = EMPTY;
	[self displayCardAt: i];
	[deck putIntoCrib: card];
    }

    return self;
}


- (BOOL) faceUp
//
// Computer's cards are displayed face down.
//
{
    return NO;
}


- sortHand
{
    [super sortHand];
    [self makeknown: hand num: FULLHAND];
    return self;
}


- makeknown: (CARD *) cards num: (int) n
{
    register  int	i;

    for( i = 0; i < n; i++ )  {
	known[ knownum++ ] = cards[i];
    }
    
    return self;
}


- makeknown: (CARD) card
{
    known[ knownum++ ] = card;
    
    return self;
}


@end
