二人麻将(机器人)【源码】

[复制链接]

该用户从未签到

2380

主题

2433

帖子

9139

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9139
QQ
跳转到指定楼层
楼主
发表于 2017-6-13 11:52:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

想要查看内容赶紧注册登陆吧!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
#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_byCardCount++] = m_byCardData;
    }

    if( bFound )
        m_byCardData[byCount-1] = 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_byCardCount++] = m_byCardData;
    }

    if( bFound)
        m_byCardData[byCount-1] = 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[m_byEnjoinOutCount++] = byActionCard;
            if( byActionCard%9 < 7 )
                m_byEnjoinOutCard[m_byEnjoinOutCount++] = byActionCard+3;
            break;
        }
    case WIK_CENTER:
        {
            m_nActionScore = 300;
            VERIFY( RemoveCardData(byActionCard-1) );
            VERIFY( RemoveCardData(byActionCard+1) );
            //禁止出的牌
            m_byEnjoinOutCount = 0;
            m_byEnjoinOutCard[m_byEnjoinOutCount++] = byActionCard;
            break;
        }
    case WIK_RIGHT:
        {
            m_nActionScore = 300;
            VERIFY( RemoveCardData(byActionCard-2) );
            VERIFY( RemoveCardData(byActionCard-1) );
            //禁止出的牌
            m_byEnjoinOutCount = 0;
            m_byEnjoinOutCard[m_byEnjoinOutCount++] = byActionCard;
            if( byActionCard%9 > 3 )
                m_byEnjoinOutCard[m_byEnjoinOutCount++] = byActionCard-3;
            break;
        }
    case WIK_PENG:
        {
            m_nActionScore = 300;;
            VERIFY( RemoveCardData(byActionCard) );
            VERIFY( RemoveCardData(byActionCard) );
            //禁止出的牌
            m_byEnjoinOutCount = 0;
            m_byEnjoinOutCard[m_byEnjoinOutCount++] = 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_byThreeCount*3] = m_byCardData;
                m_byThreeCard[m_byThreeCount*3+1] = m_byCardData;
                m_byThreeCard[m_byThreeCount*3+2] = m_byCardData;
               
                //递归
                m_byThreeCount++;
                m_nScoreThree += 300;
                m_bSelect[byIndex1] = true;
                m_bSelect[byIndex2] = true;
                AnalyseThree();
                m_bSelect[byIndex1] = false;
                m_bSelect[byIndex2] = false;
                m_nScoreThree -= 300;
                m_byThreeCount--;
            }
            //搜索连牌
            if( SearchLinkCard(m_byCardData,byIndex1,byIndex2) )
            {
                //临时记录
                m_byThreeCard[m_byThreeCount*3] = m_byCardData;
                m_byThreeCard[m_byThreeCount*3+1] = m_byCardData+1;
                m_byThreeCard[m_byThreeCount*3+2] = m_byCardData+2;

                //递归
                m_byThreeCount++;
                m_nScoreThree += 300;
                m_bSelect[byIndex1] = true;
                m_bSelect[byIndex2] = true;
                AnalyseThree();
                m_bSelect[byIndex1] = false;
                m_bSelect[byIndex2] = 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_byRemainThreeCount++] = 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_byTwoCount*2] = m_byRemainThree;
                m_byTwoCard[m_byTwoCount*2+1] = m_byRemainThree[byIndex];

                //判断将
                m_byTwoCount++;
                int nGoodSame = 90;
                if( !m_bHaveJiang )
                {
                    m_bHaveJiang = true;
                    nGoodSame = 120;
                }
                //递归
                m_nScoreTwo += nGoodSame;
                m_bSelect[byIndex] = true;
                AnalyseTwo();
                m_bSelect[byIndex] = false;
                if( 120 == nGoodSame )
                    m_bHaveJiang = false;
                m_nScoreTwo -= nGoodSame;
                m_byTwoCount--;
            }
            //搜索紧连牌
            if( SearchLinkCardRemain(m_byRemainThree,0,byIndex,i+1) )
            {
                //临时记录
                m_byTwoCard[m_byTwoCount*2] = m_byRemainThree;
                m_byTwoCard[m_byTwoCount*2+1] = m_byRemainThree[byIndex];

                //判断边
                m_byTwoCount++;
                int nGoodLink;
                if( IsEdge(m_byRemainThree,m_byRemainThree[byIndex]) )
                    nGoodLink = 80;
                else nGoodLink = 100;
                //递归
                m_nScoreTwo += nGoodLink;
                m_bSelect[byIndex] = true;
                AnalyseTwo();
                m_bSelect[byIndex] = false;
                m_nScoreTwo -= nGoodLink;
                m_byTwoCount--;
            }
            //搜索有卡的连牌
            if( SearchLinkCardRemain(m_byRemainThree,1,byIndex,i+1) )
            {               
                //临时记录
                m_byTwoCard[m_byTwoCount*2] = m_byRemainThree;
                m_byTwoCard[m_byTwoCount*2+1] = m_byRemainThree[byIndex];

                //判断边
                m_byTwoCount++;
                int nGoodLink;
                if( IsEdge(m_byRemainThree,m_byRemainThree[byIndex]) )
                    nGoodLink = 70;
                else nGoodLink = 90;
                //递归
                m_nScoreTwo += nGoodLink;
                m_bSelect[byIndex] = true;
                AnalyseTwo();
                m_bSelect[byIndex] = 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_byRemainTwoCount++] = 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[MAX_COUNT];
    BYTE byCardTwoCount = 0;
    bool bTeamHave = false;
    //设置变量
    for( int i = 0;i < m_byRemainThreeCount;i++ )
        byCardTwo[byCardTwoCount++] = m_byRemainThree;
    //仅有一对
    if( byCardTwoCount == 2 )                                                //如果只有两张牌
    {
        if( byCardTwo[0] == byCardTwo[1] )                                //胡牌
        {
            if( !IsEnjoinOutCard(byCardTwo[0]) )
                m_byBadlyCard = byCardTwo[0];                                
            return;
        }
        m_byRemainTwoCount = 2;
        m_byRemainTwo[0] = byCardTwo[0];
        m_byRemainTwo[1] = byCardTwo[1];
        AnalyseOne();
    }
    else
    {
        bool bSameHave = false;
        int nMinScore = 33;
        int nScore[8];
        memset(nScore,33,sizeof(nScore));
        for( BYTE j = 0;j < byCardTwoCount/2;j++ )                    //循环纪录每张牌的分数
        {
            if( byCardTwo[j*2] == byCardTwo[j*2 + 1] )                //对子
            {
                if( bSameHave )
                {
                    nScore[j] = 6;
                }
                else
                {
                    nScore[j] = 8;
                    bSameHave = true;
                }
            }
            else if( byCardTwo[j*2] == byCardTwo[j*2+1] - 1 )        //紧连门子
            {
                if( byCardTwo[j*2]%9 == 0 || byCardTwo[j*2+1]%9 == 8 )
                {
                    nScore[j] = 4;
                }
                else
                {
                    nScore[j] = 7;
                }
            }
            else                                                    //漏一个门子
            {
                if( byCardTwo[j*2]%9 == 0 || byCardTwo[j*2+1]%9 == 8 )
                    nScore[j] = 3;
                else
                    nScore[j] = 5;
            }
            
        }
        for( BYTE k = 0;k < byCardTwoCount/2;k++)                        //找出分数最小的一张牌就是最差的一张
        {
            if( nScore[k] < nMinScore )
            {
                if( byCardTwo[k*2] % 9 == 0 && !IsEnjoinOutCard(byCardTwo[k*2]) )
                {
                    m_byBadlyCard = byCardTwo[k*2];
                }
                else if( byCardTwo[k*2+1] % 9 == 8 && !IsEnjoinOutCard(byCardTwo[k*2+1]) )
                {
                    m_byBadlyCard = byCardTwo[k*2+1];
                }
                else
                {
                    int nIndex = rand()%2;
                    if( IsEnjoinOutCard(byCardTwo[k*2+nIndex]) )
                    {
                        nIndex = (nIndex+1)%2;
                        if( IsEnjoinOutCard(byCardTwo[k*2+nIndex]) ) continue;
                        else m_byBadlyCard = byCardTwo[k*2+nIndex];
                    }
                    else m_byBadlyCard = byCardTwo[k*2+nIndex];
                }
                nMinScore = nScore[k];
            }
        }
    }
}

//判断牌是否禁止出
bool CAndroidAI::IsEnjoinOutCard( BYTE byCard )
{
    for( BYTE i = 0; i < m_byEnjoinOutCount; i++ )
    {
        if( byCard == m_byEnjoinOutCard )
            return true;
    }
    return false;
}

/////////////////////////////////////////////////////////////////////////////////////

分享到:  QQ好友和群QQ好友和群
收藏收藏
回复

使用道具 举报

快速回复高级模式
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表