304 lines
6.5 KiB
C++
304 lines
6.5 KiB
C++
|
/***************************************************************************/
|
||
|
/** Microsoft Windows **/
|
||
|
/** Copyright(c) Microsoft Corp., 1991, 1992 **/
|
||
|
/***************************************************************************/
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
computer.cpp
|
||
|
|
||
|
keithmo
|
||
|
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "hearts.h"
|
||
|
|
||
|
#include "main.h"
|
||
|
#include "resource.h"
|
||
|
|
||
|
|
||
|
//
|
||
|
// Static members.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// This array is used to prioritize the search for cards
|
||
|
// to pass. This basically maps the irritating A-K ordering
|
||
|
// used by CARDS.DLL into a more appropriate 2-A ordering.
|
||
|
//
|
||
|
|
||
|
int computer :: _VectorPriority[13] =
|
||
|
{
|
||
|
VECTOR_ACE,
|
||
|
VECTOR_KING,
|
||
|
VECTOR_QUEEN,
|
||
|
VECTOR_JACK,
|
||
|
VECTOR_10,
|
||
|
VECTOR_9,
|
||
|
VECTOR_8,
|
||
|
VECTOR_7,
|
||
|
VECTOR_6,
|
||
|
VECTOR_5,
|
||
|
VECTOR_4,
|
||
|
VECTOR_3,
|
||
|
VECTOR_2
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// This array is used to prioritize the card suits.
|
||
|
//
|
||
|
|
||
|
int computer :: _SuitPriority[4] =
|
||
|
{
|
||
|
INDEX_HEARTS,
|
||
|
INDEX_SPADES,
|
||
|
INDEX_DIAMONDS,
|
||
|
INDEX_CLUBS
|
||
|
};
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
computer constructor
|
||
|
|
||
|
****************************************************************************/
|
||
|
computer :: computer(int n) : player(n, n)
|
||
|
{
|
||
|
CString newname;
|
||
|
TCHAR buf[MAXNAMELENGTH+1];
|
||
|
|
||
|
*buf = '\0';
|
||
|
RegEntry Reg(szRegPath);
|
||
|
Reg.GetString(regvalPName[n-1], buf, sizeof(buf));
|
||
|
newname = buf;
|
||
|
|
||
|
if (newname.IsEmpty())
|
||
|
newname.LoadString(IDS_P1NAME + n - 1);
|
||
|
|
||
|
CClientDC dc(::pMainWnd);
|
||
|
SetName(newname, dc);
|
||
|
|
||
|
} // computer :: computer
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
Keith: Make sure you Select(TRUE) cards you select, and
|
||
|
SetMode(DONE_SELECTING) before you return.
|
||
|
|
||
|
****************************************************************************/
|
||
|
void computer :: SelectCardsToPass()
|
||
|
{
|
||
|
//
|
||
|
// This will hold the total number of cards that
|
||
|
// have been passed.
|
||
|
//
|
||
|
|
||
|
int cPassed = 0;
|
||
|
int i;
|
||
|
int nSuit;
|
||
|
|
||
|
//
|
||
|
// First we must build our database.
|
||
|
//
|
||
|
|
||
|
ComputeVectors();
|
||
|
|
||
|
//
|
||
|
// Priority 1: Lose the Queen, King, and Ace of Spades.
|
||
|
//
|
||
|
|
||
|
PassCardsInVector( QuerySpadesVector() & QKA_CARDS,
|
||
|
INDEX_SPADES,
|
||
|
&cPassed );
|
||
|
|
||
|
//
|
||
|
// Priority 2: Lose the Jack, Queen, King, and Ace of Hearts.
|
||
|
//
|
||
|
|
||
|
PassCardsInVector( QueryHeartsVector() & JQKA_CARDS,
|
||
|
INDEX_HEARTS,
|
||
|
&cPassed );
|
||
|
|
||
|
//
|
||
|
// Priority 3: Pass any high cards not accompanied by two or
|
||
|
// more low cards.
|
||
|
//
|
||
|
|
||
|
for( i = 0 ; ( i < 4 ) && ( cPassed < 3 ) ; i++ )
|
||
|
{
|
||
|
nSuit = _SuitPriority[i];
|
||
|
|
||
|
if( nSuit == INDEX_SPADES )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if( CountBits( _CardVectors[nSuit] & LOW_CARDS ) < 2 )
|
||
|
{
|
||
|
PassCardsInVector( _CardVectors[nSuit] & HIGH_CARDS,
|
||
|
nSuit,
|
||
|
&cPassed );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Priority 4: If we have the opportunity to "short suit" our
|
||
|
// hand, do it.
|
||
|
//
|
||
|
|
||
|
for( i = 0 ; ( i < 4 ) && ( cPassed < 3 ) ; i++ )
|
||
|
{
|
||
|
nSuit = _SuitPriority[i];
|
||
|
|
||
|
if( CountBits( _CardVectors[nSuit] ) <= ( 3 - cPassed ) )
|
||
|
{
|
||
|
PassCardsInVector( _CardVectors[nSuit],
|
||
|
nSuit,
|
||
|
&cPassed );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Priority 5: Hell, I don't know. Just find some cards to pass.
|
||
|
//
|
||
|
|
||
|
for( i = 0 ; ( i < 4 ) && ( cPassed < 3 ) ; i++ )
|
||
|
{
|
||
|
nSuit = _SuitPriority[i];
|
||
|
|
||
|
PassCardsInVector( _CardVectors[nSuit],
|
||
|
nSuit,
|
||
|
&cPassed );
|
||
|
}
|
||
|
|
||
|
SetMode( DONE_SELECTING );
|
||
|
|
||
|
} // computer :: SelectCardsToPass
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
ComputeVectors
|
||
|
|
||
|
This method sets the _CardVectors[] array to reflect the current set
|
||
|
of cards held by the computer.
|
||
|
|
||
|
****************************************************************************/
|
||
|
void computer :: ComputeVectors( void )
|
||
|
{
|
||
|
//
|
||
|
// First, clear out the current vectors.
|
||
|
//
|
||
|
|
||
|
_CardVectors[0] = 0;
|
||
|
_CardVectors[1] = 0;
|
||
|
_CardVectors[2] = 0;
|
||
|
_CardVectors[3] = 0;
|
||
|
|
||
|
//
|
||
|
// Now, scan the currently held cards, updating the vectors.
|
||
|
//
|
||
|
|
||
|
for( int i = 0 ; i < 13 ; i++ )
|
||
|
{
|
||
|
if( cd[i].IsInHand() )
|
||
|
{
|
||
|
AddCard( cd[i].ID() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // computer :: ComputeVectors
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
PassCardsInVector
|
||
|
|
||
|
****************************************************************************/
|
||
|
void computer :: PassCardsInVector( int nVector, int nSuit, int * pcPassed )
|
||
|
{
|
||
|
int tmpVector;
|
||
|
|
||
|
//
|
||
|
// Don't even try if the vector is already empty or we've already
|
||
|
// passed three cards.
|
||
|
//
|
||
|
|
||
|
if( ( nVector == 0 ) || ( *pcPassed >= 3 ) )
|
||
|
return;
|
||
|
|
||
|
//
|
||
|
// Scan the cards in our hand. Pass all of those whose suit
|
||
|
// matches nSuit & are in nVector. Prioritize the search
|
||
|
// via the _VectorPriority array.
|
||
|
//
|
||
|
|
||
|
for( int m = 0 ; ( m < 13 ) && ( *pcPassed < 3 ) ; m++ )
|
||
|
{
|
||
|
tmpVector = nVector & _VectorPriority[m];
|
||
|
|
||
|
if( tmpVector == 0 )
|
||
|
continue;
|
||
|
|
||
|
for( int i = 0 ; i < 13 ; i++ )
|
||
|
{
|
||
|
if( cd[i].Suit() != nSuit )
|
||
|
continue;
|
||
|
|
||
|
if( ( tmpVector & CardToVector( cd[i].ID() ) ) == 0 )
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// We found a card. Mark it as selected.
|
||
|
//
|
||
|
|
||
|
cd[i].Select( TRUE );
|
||
|
|
||
|
//
|
||
|
// Remove the card from our local vector. Also
|
||
|
// remove it from the card database and update the
|
||
|
// number of passed cards.
|
||
|
//
|
||
|
|
||
|
nVector &= ~CardToVector( cd[i].ID() );
|
||
|
RemoveCard( cd[i].ID() );
|
||
|
(*pcPassed)++;
|
||
|
|
||
|
//
|
||
|
// Since there's always *exactly* one bit set in
|
||
|
// tmpVector, and we've found the card for that
|
||
|
// bit, we can exit this inner loop.
|
||
|
//
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the vector has become empty, we can terminate the
|
||
|
// outer loop.
|
||
|
//
|
||
|
|
||
|
if( nVector == 0 )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} // computer :: PassCardsInVector
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
CountBits
|
||
|
|
||
|
****************************************************************************/
|
||
|
int computer :: CountBits( int x ) const
|
||
|
{
|
||
|
x = ( ( x >> 1 ) & 0x5555 ) + ( x & 0x5555 );
|
||
|
x = ( ( x >> 2 ) & 0x3333 ) + ( x & 0x3333 );
|
||
|
x = ( ( x >> 4 ) & 0x0f0f ) + ( x & 0x0f0f );
|
||
|
x = ( ( x >> 8 ) & 0x00ff ) + ( x & 0x00ff );
|
||
|
|
||
|
return x;
|
||
|
|
||
|
} // computer :: CountBits
|