二人麻将(机器人)【源码】
#include "StdAfx.h"#include ".\androidai.h"
/////////////////////////////////////////////////////////////////////////////////////
//CAndroidAIBase
CAndroidAIBase::CAndroidAIBase()
{
memset(m_byCardData,0xff,sizeof(m_byCardData));
}
CAndroidAIBase::~CAndroidAIBase()
{
}
//设置牌
void CAndroidAIBase::SetCardData( const BYTE cbCardData[],BYTE byCardCount )
{
//复制牌
CopyMemory(m_byCardData,cbCardData,sizeof(BYTE)*byCardCount);
m_byCardCount = byCardCount;
//初始化
ZeroMemory(m_bSelect,sizeof(m_bSelect));
//
ZeroMemory(m_byThreeCard,sizeof(m_byThreeCard));
m_byThreeCount = 0;
ZeroMemory(m_byGoodThreeCard,sizeof(m_byGoodThreeCard));
m_byGoodThreeCount = 0;
//
ZeroMemory(m_byTwoCard,sizeof(m_byTwoCard));
m_byTwoCount = 0;
ZeroMemory(m_byGoodTwoCard,sizeof(m_byGoodTwoCard));
m_byGoodTwoCount = 0;
//
ZeroMemory(m_byRemainThree,sizeof(m_byRemainThree));
m_byRemainThreeCount = 0;
ZeroMemory(m_byRemainTwo,sizeof(m_byRemainTwo));
m_byRemainTwoCount = 0;
//
m_nMaxScoreThree = m_nMaxScoreTwo = 0;
m_nActionScore = 0;
m_nScoreThree = m_nScoreTwo = 0;
//
m_bHaveJiang = false;
//
m_byBadlyCard = 0xff;
}
//获取最差牌
BYTE CAndroidAIBase::GetBadlyCard()
{
return m_byBadlyCard;
}
//获取最大分
int CAndroidAIBase::GetMaxScore()
{
return m_nActionScore+m_nMaxScoreThree+m_nMaxScoreTwo;
}
//两只牌是否是边的
bool CAndroidAIBase::IsEdge( BYTE byCard1,BYTE byCard2 )
{
if( 0 == byCard1%9 || 8 == byCard2%9 )
return true;
return false;
}
//搜索相同牌
bool CAndroidAIBase::SearchSameCard( BYTE byCardData,BYTE &byIndex1,BYTE &byIndex2 )
{
//
byIndex1 = FindIndex(byCardData);
if( byIndex1 == 0xff ) return false;
byIndex2 = FindIndex(byCardData,byIndex1+1);
if( byIndex2 == 0xff ) return false;
return true;
}
//搜索连牌
bool CAndroidAIBase::SearchLinkCard( BYTE byCardData,BYTE &byIndex1,BYTE &byIndex2 )
{
//效验
if( byCardData >= 27 ) return false;
//第二,三只
BYTE byCard1 = byCardData+1;
BYTE byCard2 = byCardData+2;
if( byCard1 >= 27 || byCard2 >= 27 || byCardData/9 != byCard1/9 || byCardData/9 != byCard2/9 )
return false;
//寻找
byIndex1 = FindIndex(byCard1);
if( byIndex1 == 0xff ) return false;
byIndex2 = FindIndex(byCard2);
if( byIndex2 == 0xff ) return false;
return true;
}
//搜索两只同牌
bool CAndroidAIBase::SearchSameCardRemain( BYTE byCardData,BYTE &byIndex,BYTE byStart )
{
byIndex = FindIndexRemain(byCardData,byStart);
return 0xff==byIndex?false:true;
}
//搜索有卡连牌
bool CAndroidAIBase::SearchLinkCardRemain( BYTE byCardData,BYTE byLinkType,BYTE &byIndex,BYTE byStart )
{
//验证
if( byCardData >= 27 ) return false;
//判断类型
BYTE byCard1 = 0xff;
if( 0 == byLinkType ) //紧连
byCard1 = byCardData+1;
else if( 1 == byLinkType ) //有卡
byCard1 = byCardData+2;
//过滤
if( byCard1 >= 27 || byCardData/9 != byCard1/9 ) return false;
byIndex = FindIndexRemain(byCard1,byStart);
return 0xff==byIndex?false:true;
}
//搜索牌
BYTE CAndroidAIBase::FindIndex( BYTE byCardData,BYTE byStart )
{
for( BYTE i = byStart; i < m_byCardCount; i++ )
{
if( byCardData == m_byCardData && !m_bSelect )
return i;
}
return 0xff;
}
//在移除最佳三只后搜索牌
BYTE CAndroidAIBase::FindIndexRemain( BYTE byCardData,BYTE byStart )
{
for( BYTE i = byStart; i < m_byRemainThreeCount; i++ )
{
if( byCardData == m_byRemainThree && !m_bSelect )
return i;
}
return 0xff;
}
//移除牌
bool CAndroidAIBase::RemoveCard( BYTE byCardIndex )
{
//效验
ASSERT( m_byCardCount > 0 );
if( m_byCardCount == 0 ) return false;
ASSERT( byCardIndex >= 0 && byCardIndex < MAX_INDEX );
if( byCardIndex < 0 || byCardIndex >= MAX_INDEX ) return false;
//删除
BYTE byCount = m_byCardCount;
m_byCardCount = 0;
bool bFound = false;
for( BYTE i = 0; i < byCount; i++ )
{
if( i == byCardIndex )
{
bFound = true;
continue;
}
m_byCardData = m_byCardData;
}
if( bFound )
m_byCardData = 0xff;
return bFound;
}
//移除牌值
bool CAndroidAIBase::RemoveCardData( BYTE byCardData )
{
//效验
ASSERT( m_byCardCount > 0 );
if( m_byCardCount == 0 ) return false;
//删除
BYTE byCount = m_byCardCount;
m_byCardCount = 0;
bool bFound = false;
for( BYTE i = 0; i < byCount; i++ )
{
if( !bFound && m_byCardData == byCardData )
{
bFound = true;
continue;
}
m_byCardData = m_byCardData;
}
if( bFound)
m_byCardData = 0xff;
return bFound;
}
/////////////////////////////////////////////////////////////////////////////////////
//CAndroidAI
CAndroidAI::CAndroidAI(void)
{
ZeroMemory(m_byEnjoinOutCard,sizeof(m_byEnjoinOutCard));
m_byEnjoinOutCount = 0;
}
CAndroidAI::~CAndroidAI(void)
{
}
//思考
void CAndroidAI::Think()
{
//重置
m_nMaxScoreThree = 0;
m_nMaxScoreTwo = 0;
//分析三只
AnalyseThree();
//如果没三只
BYTE i;
if( m_nMaxScoreThree == 0 || m_byRemainThreeCount == 0 )
{
m_byRemainThreeCount = m_byCardCount;
for( i = 0; i < m_byRemainThreeCount; i++ )
m_byRemainThree = m_byCardData;
}
//分析两只
AnalyseTwo();
if( m_nMaxScoreTwo == 0 )
{
m_byRemainTwoCount = m_byRemainThreeCount;
for( i = 0; i < m_byRemainTwoCount; i++ )
m_byRemainTwo = m_byRemainThree;
}
//如果全部是两只
if( m_byRemainTwoCount == 0 )
{
SearchTwo();
return;
}
//分析一只
AnalyseOne();
}
//从最佳两只牌组合中搜索最差牌
BYTE CAndroidAI::GetBadlyIn2Card()
{
BYTE byBadly = 0xff;
int nMin = 33;
int nScore;
BYTE byCard;
for( BYTE i = 0; i < m_byGoodTwoCount*2; i++ )
{
byCard = m_byGoodTwoCard;
if( IsEnjoinOutCard(byCard) ) continue;
if( byCard >= 27 ) //如果是字
{
nScore = 2;
}
else if( byCard%9 == 0 || byCard%9 == 8 ) //如果是一或者九
{
nScore = 6;
}
else
{
nScore = 10;
}
nScore += AddScore(byCard);
if( nScore < nMin )
{
nMin = nScore;
byBadly = byCard;
}
}
return byBadly;
}
//从最佳三只牌组合中搜索最差牌
BYTE CAndroidAI::GetBadlyIn3Card()
{
BYTE byBadly = 0xff;
int nMin = 33;
int nScore;
BYTE byCard;
for( BYTE i = 0; i < m_byGoodThreeCount*3; i++ )
{
byCard = m_byGoodThreeCard;
if( IsEnjoinOutCard(byCard) ) continue;
if( byCard >= 27 ) //如果是字
{
nScore = 2;
}
else if( byCard%9 == 0 || byCard%9 == 8 ) //如果是一或者九
{
nScore = 6;
}
else
{
nScore = 10;
}
nScore += AddScore(byCard);
if( nScore < nMin )
{
nMin = nScore;
byBadly = byCard;
}
}
return byBadly;
}
//设置禁止出的牌
void CAndroidAI::SetEnjoinOutCard( const BYTE cbEnjoinOutCard[],BYTE cbEnjoinOutCount )
{
m_byEnjoinOutCount = cbEnjoinOutCount;
if( m_byEnjoinOutCount > 0 )
{
CopyMemory(m_byEnjoinOutCard,cbEnjoinOutCard,sizeof(BYTE)*cbEnjoinOutCount);
}
}
//模拟操作
void CAndroidAI::SetAction( BYTE byActionMask,BYTE byActionCard )
{
//验证
ASSERT( byActionCard >=0 && byActionCard < 34 );
if( byActionCard >= 34 ) return;
//枚举
switch( byActionMask )
{
case WIK_LEFT:
{
m_nActionScore = 300;
VERIFY( RemoveCardData(byActionCard+1) );
VERIFY( RemoveCardData(byActionCard+2) );
//禁止出的牌
m_byEnjoinOutCount = 0;
m_byEnjoinOutCard = byActionCard;
if( byActionCard%9 < 7 )
m_byEnjoinOutCard = byActionCard+3;
break;
}
case WIK_CENTER:
{
m_nActionScore = 300;
VERIFY( RemoveCardData(byActionCard-1) );
VERIFY( RemoveCardData(byActionCard+1) );
//禁止出的牌
m_byEnjoinOutCount = 0;
m_byEnjoinOutCard = byActionCard;
break;
}
case WIK_RIGHT:
{
m_nActionScore = 300;
VERIFY( RemoveCardData(byActionCard-2) );
VERIFY( RemoveCardData(byActionCard-1) );
//禁止出的牌
m_byEnjoinOutCount = 0;
m_byEnjoinOutCard = byActionCard;
if( byActionCard%9 > 3 )
m_byEnjoinOutCard = byActionCard-3;
break;
}
case WIK_PENG:
{
m_nActionScore = 300;;
VERIFY( RemoveCardData(byActionCard) );
VERIFY( RemoveCardData(byActionCard) );
//禁止出的牌
m_byEnjoinOutCount = 0;
m_byEnjoinOutCard = byActionCard;
break;
}
case WIK_GANG:
{
VERIFY( RemoveCardData(byActionCard) );
BYTE byIndex = FindIndex(byActionCard);
if( byIndex != 0xff )
{
m_nActionScore = 300;
VERIFY( RemoveCardData(byActionCard) );
VERIFY( RemoveCardData(byActionCard) );
byIndex = FindIndex(byActionCard);
if( byIndex != 0xff )
VERIFY( RemoveCardData(byActionCard) );
}
break;
}
default:
ASSERT( FALSE );
}
}
//重置得分
void CAndroidAI::ResetScore()
{
m_nActionScore = m_nMaxScoreThree = m_nMaxScoreTwo = 0;
}
//加权
int CAndroidAI::AddScore( BYTE byCardData )
{
int nScore = 0;
if( byCardData >= 27 )
{
return 0;
}
if( byCardData%9 != 0 && FindIndex(byCardData-1) != 0xff ) //如果剩余的牌中有比其少一的牌
{
if( byCardData%9 != 1 ) //如果当前牌不是二类即加3
{
nScore += 3;
}
else
{
nScore += 1;
}
}
if( byCardData%9 != 8 && FindIndex(byCardData+1) != 0xff ) //如果剩余的牌中有比起多一个的牌
{
if( byCardData%9 != 7 )
{
nScore += 3;
}
else
{
nScore += 1;
}
}
if( byCardData%9 > 1 && FindIndex(byCardData-2) != 0xff ) //如果剩余的牌中有比其少二的牌(如3—5,1_3等)
{
nScore += 2;
}
if( byCardData%9 < 7 && FindIndex(byCardData+2) != 0xff ) //如果剩余的牌中有比其多二的牌
{
nScore += 2;
}
return nScore;
}
//分析三只
void CAndroidAI::AnalyseThree()
{
BYTE byIndex1,byIndex2;
for( BYTE i = 0; i < m_byCardCount; i++ )
{
if( !m_bSelect )
{
m_bSelect = true;
//搜索三只
if( SearchSameCard(m_byCardData,byIndex1,byIndex2) )
{
//临时记录
m_byThreeCard = m_byCardData;
m_byThreeCard = m_byCardData;
m_byThreeCard = m_byCardData;
//递归
m_byThreeCount++;
m_nScoreThree += 300;
m_bSelect = true;
m_bSelect = true;
AnalyseThree();
m_bSelect = false;
m_bSelect = false;
m_nScoreThree -= 300;
m_byThreeCount--;
}
//搜索连牌
if( SearchLinkCard(m_byCardData,byIndex1,byIndex2) )
{
//临时记录
m_byThreeCard = m_byCardData;
m_byThreeCard = m_byCardData+1;
m_byThreeCard = m_byCardData+2;
//递归
m_byThreeCount++;
m_nScoreThree += 300;
m_bSelect = true;
m_bSelect = true;
AnalyseThree();
m_bSelect = false;
m_bSelect = false;
m_nScoreThree -= 300;
m_byThreeCount--;
}
m_bSelect = false;
}
}
//如果搜索到分数更高的
if( m_nScoreThree > m_nMaxScoreThree )
{
//记录剩下的
m_byRemainThreeCount = 0;
m_nMaxScoreThree = m_nScoreThree;
for( i = 0; i < m_byCardCount; i++ )
{
if( !m_bSelect )
m_byRemainThree = m_byCardData;
}
//记录最佳三只组合
m_byGoodThreeCount = m_byThreeCount;
CopyMemory(m_byGoodThreeCard,m_byThreeCard,sizeof(m_byThreeCard));
}
}
//分析两只
void CAndroidAI::AnalyseTwo()
{
BYTE byIndex;
for( BYTE i = 0; i < m_byRemainThreeCount; i++ )
{
if( !m_bSelect )
{
m_bSelect = true;
//搜索两只相同
if( SearchSameCardRemain(m_byRemainThree,byIndex,i+1) )
{
//临时记录
m_byTwoCard = m_byRemainThree;
m_byTwoCard = m_byRemainThree;
//判断将
m_byTwoCount++;
int nGoodSame = 90;
if( !m_bHaveJiang )
{
m_bHaveJiang = true;
nGoodSame = 120;
}
//递归
m_nScoreTwo += nGoodSame;
m_bSelect = true;
AnalyseTwo();
m_bSelect = false;
if( 120 == nGoodSame )
m_bHaveJiang = false;
m_nScoreTwo -= nGoodSame;
m_byTwoCount--;
}
//搜索紧连牌
if( SearchLinkCardRemain(m_byRemainThree,0,byIndex,i+1) )
{
//临时记录
m_byTwoCard = m_byRemainThree;
m_byTwoCard = m_byRemainThree;
//判断边
m_byTwoCount++;
int nGoodLink;
if( IsEdge(m_byRemainThree,m_byRemainThree) )
nGoodLink = 80;
else nGoodLink = 100;
//递归
m_nScoreTwo += nGoodLink;
m_bSelect = true;
AnalyseTwo();
m_bSelect = false;
m_nScoreTwo -= nGoodLink;
m_byTwoCount--;
}
//搜索有卡的连牌
if( SearchLinkCardRemain(m_byRemainThree,1,byIndex,i+1) )
{
//临时记录
m_byTwoCard = m_byRemainThree;
m_byTwoCard = m_byRemainThree;
//判断边
m_byTwoCount++;
int nGoodLink;
if( IsEdge(m_byRemainThree,m_byRemainThree) )
nGoodLink = 70;
else nGoodLink = 90;
//递归
m_nScoreTwo += nGoodLink;
m_bSelect = true;
AnalyseTwo();
m_bSelect = false;
m_nScoreTwo -= nGoodLink;
m_byTwoCount--;
}
m_bSelect = false;
}
}
//如果有分数更高的
if( m_nScoreTwo > m_nMaxScoreTwo )
{
//记录剩下的
m_nMaxScoreTwo = m_nScoreTwo;
m_byRemainTwoCount = 0;
for( i = 0; i < m_byRemainThreeCount; i++ )
{
if( !m_bSelect )
m_byRemainTwo = m_byRemainThree;
}
//记录最佳两只组合
m_byGoodTwoCount = m_byTwoCount;
CopyMemory(m_byGoodTwoCard,m_byTwoCard,sizeof(m_byTwoCard));
}
}
//分析单只
void CAndroidAI::AnalyseOne()
{
BYTE byCard;
int nScore;
int nMin = 33;
for(int i = 0;i < m_byRemainTwoCount;i++ ) //找出最差的一张牌
{
byCard = m_byRemainTwo;
if( IsEnjoinOutCard(byCard) ) continue;
if( byCard >= 27 ) //如果是字
{
nScore = 2;
}
else if( byCard%9 == 0 || byCard%9 == 8 ) //如果是一或者九
{
nScore = 6;
}
else
{
nScore = 10;
}
nScore += AddScore(byCard);
if( nScore < nMin )
{
nMin = nScore;
m_byBadlyCard = byCard;
}
}
}
//从两只组合中分析
void CAndroidAI::SearchTwo()
{
//定义变量
BYTE byCardTwo;
BYTE byCardTwoCount = 0;
bool bTeamHave = false;
//设置变量
for( int i = 0;i < m_byRemainThreeCount;i++ )
byCardTwo = m_byRemainThree;
//仅有一对
if( byCardTwoCount == 2 ) //如果只有两张牌
{
if( byCardTwo == byCardTwo ) //胡牌
{
if( !IsEnjoinOutCard(byCardTwo) )
m_byBadlyCard = byCardTwo;
return;
}
m_byRemainTwoCount = 2;
m_byRemainTwo = byCardTwo;
m_byRemainTwo = byCardTwo;
AnalyseOne();
}
else
{
bool bSameHave = false;
int nMinScore = 33;
int nScore;
memset(nScore,33,sizeof(nScore));
for( BYTE j = 0;j < byCardTwoCount/2;j++ ) //循环纪录每张牌的分数
{
if( byCardTwo == byCardTwo ) //对子
{
if( bSameHave )
{
nScore = 6;
}
else
{
nScore = 8;
bSameHave = true;
}
}
else if( byCardTwo == byCardTwo - 1 ) //紧连门子
{
if( byCardTwo%9 == 0 || byCardTwo%9 == 8 )
{
nScore = 4;
}
else
{
nScore = 7;
}
}
else //漏一个门子
{
if( byCardTwo%9 == 0 || byCardTwo%9 == 8 )
nScore = 3;
else
nScore = 5;
}
}
for( BYTE k = 0;k < byCardTwoCount/2;k++) //找出分数最小的一张牌就是最差的一张
{
if( nScore < nMinScore )
{
if( byCardTwo % 9 == 0 && !IsEnjoinOutCard(byCardTwo) )
{
m_byBadlyCard = byCardTwo;
}
else if( byCardTwo % 9 == 8 && !IsEnjoinOutCard(byCardTwo) )
{
m_byBadlyCard = byCardTwo;
}
else
{
int nIndex = rand()%2;
if( IsEnjoinOutCard(byCardTwo) )
{
nIndex = (nIndex+1)%2;
if( IsEnjoinOutCard(byCardTwo) ) continue;
else m_byBadlyCard = byCardTwo;
}
else m_byBadlyCard = byCardTwo;
}
nMinScore = nScore;
}
}
}
}
//判断牌是否禁止出
bool CAndroidAI::IsEnjoinOutCard( BYTE byCard )
{
for( BYTE i = 0; i < m_byEnjoinOutCount; i++ )
{
if( byCard == m_byEnjoinOutCard )
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
页:
[1]