美文网首页
五子棋人机对弈代码——之博弈树算法

五子棋人机对弈代码——之博弈树算法

作者: voidjax | 来源:发表于2017-04-16 18:30 被阅读0次

    #include

    #include

    #include

    #include

    /* Program of Game -- wuziqi Written by Zhang shuai, DEC.25th, 2010 */

    #define GRID_NUM    15 //每一行(列)的棋盘交点数

    #define GRID_COUNT  225//棋盘上交点总数

    #define BLACK       0  //黑棋用0表示

    #define WHITE       1  //白棋用1表示

    #define NOSTONE 0xFF   //没有棋子

    //这组宏定义了用以代表几种棋型的数字

    #define STWO        1  //眠二

    #define STHREE      2  //眠三

    #define SFOUR       3  //冲四

    #define TWO         4  //活二

    #define THREE       5  //活三

    #define FOUR        6  //活四

    #define FIVE        7  //五连

    #define NOTYPE      11 //未定义

    #define ANALSISED   255//已分析过的

    #define TOBEANALSIS 0  //已分析过的

    //这个宏用以检查某一坐标是否是棋盘上的有效落子点

    #define IsValidPos(x,y) ((x>=0 && x=0 && y

    //定义了枚举型的数据类型,精确,下边界,上边界

    enumENTRY_TYPE{exact,lower_bound,upper_bound};

    //哈希表中元素的结构定义

    typedefstructHASHITEM

    {

    __int64checksum;//64位校验码

    ENTRY_TYPE entry_type;//数据类型

    shortdepth;//取得此值时的层次

    shorteval;//节点的值

    }HashItem;

    typedefstructNode

    {

    intx;

    inty;

    }POINT;

    //用以表示棋子位置的结构

    typedefstruct_stoneposition

    {

    unsignedcharx;

    unsignedchary;

    }STONEPOS;

    typedefstruct_movestone

    {

    unsignedcharnRenjuID;

    POINT ptMovePoint;

    }MOVESTONE;

    //这个结构用以表示走法

    typedefstruct_stonemove

    {

    STONEPOS StonePos;//棋子位置

    intScore;//走法的分数

    }STONEMOVE;

    //=================================================================//

    intAnalysisLine(unsignedchar* position,intGridNum,intStonePos);

    intAnalysisRight(unsignedcharposition[][GRID_NUM],inti,intj);

    intAnalysisLeft(unsignedcharposition[][GRID_NUM],inti,intj);

    intAnalysisVertical(unsignedcharposition[][GRID_NUM],inti,intj);

    intAnalysisHorizon(unsignedcharposition[][GRID_NUM],inti,intj);

    intEveluate(unsignedintposition[][GRID_NUM],boolbIsWhiteTurn);

    intAddMove(intnToX,intnToY,intnPly);

    intCreatePossibleMove(unsignedcharposition[][GRID_NUM],intnPly,intnSide);

    voidMergeSort(STONEMOVE* source,intn,booldirection);

    voidMergePass(STONEMOVE* source,STONEMOVE* target,constints,constintn,constbooldirection);

    voidMerge_A(STONEMOVE* source,STONEMOVE* target,intl,intm,intr);

    voidMerge(STONEMOVE* source,STONEMOVE* target,intl,intm,intr);

    voidEnterHistoryScore(STONEMOVE* move,intdepth);

    intGetHistoryScore(STONEMOVE* move);

    voidResetHistoryTable();

    intNegaScout(intdepth,intalpha,intbeta);

    voidSearchAGoodMove(unsignedcharposition[][GRID_NUM],intType);

    intIsGameOver(unsignedcharposition[][GRID_NUM],intnDepth);

    voidUnMakeMove(STONEMOVE* move);

    unsignedcharMakeMove(STONEMOVE* move,inttype);

    void_CSearchEngine();

    voidInitializeHashKey();

    voidEnterHashTable(ENTRY_TYPE entry_type,shorteval,shortdepth,intTableNo);

    intLookUpHashTable(intalpha,intbeta,intdepth,intTableNo);

    voidHash_UnMakeMove(STONEMOVE *move,unsignedcharCurPosition[][GRID_NUM]);

    voidHash_MakeMove(STONEMOVE *move,unsignedcharCurPosition[][GRID_NUM]);

    voidCalculateInitHashKey(unsignedcharCurPosition[][GRID_NUM]);

    __int64rand64();

    longrand32();

    voidCTranspositionTable();

    void_CTranspositionTable();

    boolOnInitDialog();

    //=================================================================//

    intm_HistoryTable[GRID_NUM][GRID_NUM];//历史得分表

    STONEMOVE m_TargetBuff[225];//排序用的缓冲队列

    unsignedintm_nHashKey32[15][10][9];//32位随机树组,用以生成32位哈希值

    unsigned__int64m_ulHashKey64[15][10][9];//64位随机树组,用以生成64位哈希值

    HashItem *m_pTT[10];//置换表头指针

    unsignedintm_HashKey32;//32位哈希值

    __int64m_HashKey64;//64 位哈希值

    STONEMOVE m_MoveList[10][225];//用以记录走法的数组

    unsignedcharm_LineRecord[30];//存放AnalysisLine分析结果的数组

    intTypeRecord[GRID_NUM ][GRID_NUM][4];//存放全部分析结果的数组,有三个维度,用于存放水平、垂直、左斜、右斜 4 个方向上所有棋型分析结果

    intTypeCount[2][20];//存放统记过的分析结果的数组

    intm_nMoveCount;//此变量用以记录走法的总数

    unsignedcharCurPosition[GRID_NUM][GRID_NUM];//搜索时用于当前节点棋盘状态的数组

    STONEMOVE m_cmBestMove;//记录最佳走法的变量

    //CMoveGenerator* m_pMG;                 //走法产生器指针

    //CEveluation* m_pEval;              //估值核心指针

    intm_nSearchDepth;//最大搜索深度

    intm_nMaxDepth;//当前搜索的最大搜索深度

    unsignedcharm_RenjuBoard[GRID_NUM][GRID_NUM];//棋盘数组,用于显示棋盘

    intm_nUserStoneColor;//用户棋子的颜色

    //CSearchEngine* m_pSE;               //搜索引擎指针

    intX,Y;

    //位置重要性价值表,此表从中间向外,越往外价值越低

    intPosValue[GRID_NUM][GRID_NUM]=

    {

    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},

    {0,1,1,1,1,1,1,1,1,1,1,1,1,1,0},

    {0,1,2,2,2,2,2,2,2,2,2,2,2,1,0},

    {0,1,2,3,3,3,3,3,3,3,3,3,2,1,0},

    {0,1,2,3,4,4,4,4,4,4,4,3,2,1,0},

    {0,1,2,3,4,5,5,5,5,5,4,3,2,1,0},

    {0,1,2,3,4,5,6,6,6,5,4,3,2,1,0},

    {0,1,2,3,4,5,6,7,6,5,4,3,2,1,0},

    {0,1,2,3,4,5,6,6,6,5,4,3,2,1,0},

    {0,1,2,3,4,5,5,5,5,5,4,3,2,1,0},

    {0,1,2,3,4,4,4,4,4,4,4,3,2,1,0},

    {0,1,2,3,3,3,3,3,3,3,3,3,2,1,0},

    {0,1,2,2,2,2,2,2,2,2,2,2,2,1,0},

    {0,1,1,1,1,1,1,1,1,1,1,1,1,1,0},

    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}

    };

    //全局变量,用以统计估值函数的执行遍数

    intcount=0;

    intEveluate(unsignedcharposition[][GRID_NUM],boolbIsWhiteTurn)

    {

    inti,j,k;

    unsignedcharnStoneType;

    count++;//计数器累加

    //清空棋型分析结果

    memset(TypeRecord,TOBEANALSIS,GRID_COUNT*4*4);

    memset(TypeCount,0,40*4);

    for(i=0;i

    for(j=0;j

    {

    if(position[i][j]!=NOSTONE)

    {

    //如果水平方向上没有分析过

    if(TypeRecord[i][j][0]==TOBEANALSIS)

    AnalysisHorizon(position,i,j);

    //如果垂直方向上没有分析过

    if(TypeRecord[i][j][1]==TOBEANALSIS)

    AnalysisVertical(position,i,j);

    //如果左斜方向上没有分析过

    if(TypeRecord[i][j][2]==TOBEANALSIS)

    AnalysisLeft(position,i,j);

    //如果右斜方向上没有分析过

    if(TypeRecord[i][j][3]==TOBEANALSIS)

    AnalysisRight(position,i,j);

    }

    }

    //对分析结果进行统计,得到每种棋型的数量

    for(i=0;i

    for(j=0;j

    for(k =0;k<4;k++)

    {

    nStoneType=position[i][j];

    if(nStoneType!=NOSTONE)

    {

    switch(TypeRecord[i][j][k])

    {

    caseFIVE://五连

    TypeCount[nStoneType][FIVE]++;

    break;

    caseFOUR://活四

    TypeCount[nStoneType][FOUR]++;

    break;

    caseSFOUR://冲四

    TypeCount[nStoneType][SFOUR]++;

    break;

    caseTHREE://活三

    TypeCount[nStoneType][THREE]++;

    break;

    caseSTHREE://眠三

    TypeCount[nStoneType][STHREE]++;

    break;

    caseTWO://活二

    TypeCount[nStoneType][TWO]++;

    break;

    caseSTWO://眠二

    TypeCount[nStoneType][STWO]++;

    break;

    default:

    break;

    }

    }

    }

    //如果已五连,返回极值

    if(bIsWhiteTurn)

    {

    if(TypeCount[BLACK][FIVE])

    return-9999;

    if(TypeCount[WHITE][FIVE])

    return9999;

    }

    else

    {

    if(TypeCount[BLACK][FIVE])

    return9999;

    if(TypeCount[WHITE][FIVE])

    return-9999;

    }

    //两个冲四等于一个活四

    if(TypeCount[WHITE][SFOUR]>1)

    TypeCount[WHITE][FOUR]++;

    if(TypeCount[BLACK][SFOUR]>1)

    TypeCount[BLACK][FOUR]++;

    intWValue=0,BValue=0;

    if(bIsWhiteTurn)//轮到白棋走

    {

    if(TypeCount[WHITE][FOUR])

    return9990;//活四,白胜返回极值

    if(TypeCount[WHITE][SFOUR])

    return9980;//冲四,白胜返回极值

    if(TypeCount[BLACK][FOUR])

    return-9970;//白无冲四活四,而黑有活四,黑胜返回极值

    if(TypeCount[BLACK][SFOUR] && TypeCount[BLACK][THREE])

    return-9960;//而黑有冲四和活三,黑胜返回极值

    if(TypeCount[WHITE][THREE] && TypeCount[BLACK][SFOUR]== 0)

    return9950;//白有活三而黑没有四,白胜返回极值

    if(TypeCount[BLACK][THREE]>1 && TypeCount[WHITE][SFOUR]==0 && TypeCount[WHITE][THREE]==0 && TypeCount[WHITE][STHREE]==0)

    return-9940;//黑的活三多于一个,而白无四和三,黑胜返回极值

    if(TypeCount[WHITE][THREE]>1)

    WValue+=2000;//白活三多于一个,白棋价值加2000

    else

    //否则白棋价值加200

    if(TypeCount[WHITE][THREE])

    WValue+=200;

    if(TypeCount[BLACK][THREE]>1)

    BValue+=500;//黑的活三多于一个,黑棋价值加500

    else

    //否则黑棋价值加100

    if(TypeCount[BLACK][THREE])

    BValue+=100;

    //每个眠三加10

    if(TypeCount[WHITE][STHREE])

    WValue+=TypeCount[WHITE][STHREE]*10;

    //每个眠三加10

    if(TypeCount[BLACK][STHREE])

    BValue+=TypeCount[BLACK][STHREE]*10;

    //每个活二加4

    if(TypeCount[WHITE][TWO])

    WValue+=TypeCount[WHITE][TWO]*4;

    //每个活二加4

    if(TypeCount[BLACK][STWO])

    BValue+=TypeCount[BLACK][TWO]*4;

    //每个眠二加1

    if(TypeCount[WHITE][STWO])

    WValue+=TypeCount[WHITE][STWO];

    //每个眠二加1

    if(TypeCount[BLACK][STWO])

    BValue+=TypeCount[BLACK][STWO];

    }

    else//轮到黑棋走

    {

    if(TypeCount[BLACK][FOUR])

    return9990;//活四,黑胜返回极值

    if(TypeCount[BLACK][SFOUR])

    return9980;//冲四,黑胜返回极值

    if(TypeCount[WHITE][FOUR])

    return-9970;//活四,白胜返回极值

    if(TypeCount[WHITE][SFOUR] && TypeCount[WHITE][THREE])

    return-9960;//冲四并活三,白胜返回极值

    if(TypeCount[BLACK][THREE] && TypeCount[WHITE][SFOUR]==0)

    return9950;//黑活三,白无四。黑胜返回极值

    if(TypeCount[WHITE][THREE]>1 && TypeCount[BLACK][SFOUR]==0 && TypeCount[BLACK][THREE]==0 && TypeCount[BLACK][STHREE]==0)

    return-9940;//白的活三多于一个,而黑无四和三,白胜返回极值

    //黑的活三多于一个,黑棋价值加2000

    if(TypeCount[BLACK][THREE]>1)

    BValue+=2000;

    else

    //否则黑棋价值加200

    if(TypeCount[BLACK][THREE])

    BValue+=200;

    //白的活三多于一个,白棋价值加 500

    if(TypeCount[WHITE][THREE]>1)

    WValue+=500;

    else

    //否则白棋价值加100

    if(TypeCount[WHITE][THREE])

    WValue+=100;

    //每个眠三加10

    if(TypeCount[WHITE][STHREE])

    WValue+=TypeCount[WHITE][STHREE]*10;

    //每个眠三加10

    if(TypeCount[BLACK][STHREE])

    BValue+=TypeCount[BLACK][STHREE]*10;

    //每个活二加4

    if(TypeCount[WHITE][TWO])

    WValue+=TypeCount[WHITE][TWO]*4;

    //每个活二加4

    if(TypeCount[BLACK][STWO])

    BValue+=TypeCount[BLACK][TWO]*4;

    //每个眠二加1

    if(TypeCount[WHITE][STWO])

    WValue+=TypeCount[WHITE][STWO];

    //每个眠二加1

    if(TypeCount[BLACK][STWO])

    BValue+=TypeCount[BLACK][STWO];

    }

    //加上所有棋子的位置价值

    for(i=0;i

    for(j=0;j

    {

    nStoneType=position[i][j];

    if(nStoneType!=NOSTONE)

    if(nStoneType==BLACK)

    BValue+=PosValue[i][j];

    else

    WValue+=PosValue[i][j];

    }

    //返回估值

    if(!bIsWhiteTurn)

    returnBValue-WValue;

    else

    returnWValue-BValue;

    }

    //分析棋盘上某点在水平方向上的棋型

    intAnalysisHorizon(unsignedcharposition[][GRID_NUM],inti,intj)

    {

    //调用直线分析函数分析

    AnalysisLine(position[i],15,j);

    //拾取分析结果

    for(ints=0;s<15;s++)

    if(m_LineRecord[s]!=TOBEANALSIS)

    TypeRecord[i][s][0]= m_LineRecord[s];

    returnTypeRecord[i][j][0];

    }

    //分析棋盘上某点在垂直方向上的棋型

    intAnalysisVertical(unsignedcharposition[][GRID_NUM],inti,intj)

    {

    unsignedchartempArray[GRID_NUM];

    //将垂直方向上的棋子转入一维数组

    for(intk=0;k

    tempArray[k]=position[k][j];

    //调用直线分析函数分析

    AnalysisLine(tempArray,GRID_NUM,i);

    //拾取分析结果

    for(ints=0;s

    if(m_LineRecord[s]!=TOBEANALSIS)

    TypeRecord[s][j][1]=m_LineRecord[s];

    returnTypeRecord[i][j][1];

    }

    //分析棋盘上某点在左斜方向上的棋型

    intAnalysisLeft(unsignedcharposition[][GRID_NUM],inti,intj)

    {

    unsignedchartempArray[GRID_NUM];

    intx,y;

    if(i

    {

    y=0;

    x=j-i;

    }

    else

    {

    x=0;

    y=i-j;

    }

    //将斜方向上的棋子转入一维数组

    for(intk=0;k

    {

    if(x+k>14 || y+k>14)

    break;

    tempArray[k]=position[y+k][x+k];

    }

    //调用直线分析函数分析

    AnalysisLine(tempArray,k,j-x);

    //拾取分析结果

    for(ints=0;s

    if(m_LineRecord[s]!=TOBEANALSIS)

    TypeRecord[y+s][x+s][2]=m_LineRecord[s];

    returnTypeRecord[i][j][2];

    }

    //分析棋盘上某点在右斜方向上的棋型

    intAnalysisRight(unsignedcharposition[][GRID_NUM],inti,intj)

    {

    unsignedchartempArray[GRID_NUM];

    intx,y,realnum;

    if(14-i

    {

    y=14;

    x=j-14+i;

    realnum=14-i;

    }

    else

    {

    x=0;

    y=i+j;

    realnum=j;

    }

    //将斜方向上的棋子转入一维数组

    for(intk=0;k

    {

    if(x+k>14 || y-k<0)

    break;

    tempArray[k]=position[y-k][x+k];

    }

    //调用直线分析函数分析

    AnalysisLine(tempArray,k,j-x);

    //拾取分析结果

    for(ints=0;s

    if(m_LineRecord[s]!=TOBEANALSIS)

    TypeRecord[y-s][x+s][3]=m_LineRecord[s];

    returnTypeRecord[i][j][3];

    }

    intAnalysisLine(unsignedchar* position,intGridNum,intStonePos)

    {

    unsignedcharStoneType;

    unsignedcharAnalyLine[30];

    intnAnalyPos;

    intLeftEdge,RightEdge;

    intLeftRange,RightRange;

    if(GridNum<5)

    {

    //数组长度小于5没有意义

    memset(m_LineRecord,ANALSISED,GridNum);

    return0;

    }

    nAnalyPos=StonePos;

    memset(m_LineRecord,TOBEANALSIS,30);

    memset(AnalyLine,0x0F,30);

    //将传入数组装入AnalyLine;

    memcpy(&AnalyLine,position,GridNum);

    GridNum--;

    StoneType=AnalyLine[nAnalyPos];

    LeftEdge=nAnalyPos;

    RightEdge=nAnalyPos;

    //算连续棋子左边界

    while(LeftEdge>0)

    {

    if(AnalyLine[LeftEdge-1]!=StoneType)

    break;

    LeftEdge--;

    }

    //算连续棋子右边界

    while(RightEdge

    {

    if(AnalyLine[RightEdge+1]!=StoneType)

    break;

    RightEdge++;

    }

    LeftRange=LeftEdge;

    RightRange=RightEdge;

    //下面两个循环算出棋子可下的范围

    while(LeftRange>0)

    {

    if(AnalyLine[LeftRange -1]==!StoneType)

    break;

    LeftRange--;

    }

    while(RightRange

    {

    if(AnalyLine[RightRange+1]==!StoneType)

    break;

    RightRange++;

    }

    //如果此范围小于4则分析没有意义

    if(RightRange-LeftRange<4)

    {

    for(intk=LeftRange;k<=RightRange;k++)

    m_LineRecord[k]=ANALSISED;

    returnfalse;

    }

    //将连续区域设为分析过的,防止重复分析此一区域

    for(intk=LeftEdge;k<=RightEdge;k++)

    m_LineRecord[k]=ANALSISED;

    if(RightEdge-LeftEdge>3)

    {

    //如待分析棋子棋型为五连

    m_LineRecord[nAnalyPos]=FIVE;

    returnFIVE;

    }

    if(RightEdge-LeftEdge== 3)

    {

    //如待分析棋子棋型为四连

    boolLeftfour=false;

    if(LeftEdge>0)

    if(AnalyLine[LeftEdge-1]==NOSTONE)

    Leftfour=true;//左边有气

    if(RightEdge

    //右边未到边界

    if(AnalyLine[RightEdge+1]==NOSTONE)

    //右边有气

    if(Leftfour==true)//如左边有气

    m_LineRecord[nAnalyPos]=FOUR;//活四

    else

    m_LineRecord[nAnalyPos]=SFOUR;//冲四

    else

    if(Leftfour==true)//如左边有气

    m_LineRecord[nAnalyPos]=SFOUR;//冲四

    else

    if(Leftfour==true)//如左边有气

    m_LineRecord[nAnalyPos]=SFOUR;//冲四

    returnm_LineRecord[nAnalyPos];

    }

    if(RightEdge-LeftEdge==2)

    {

    //如待分析棋子棋型为三连

    boolLeftThree=false;

    if(LeftEdge>1)

    if(AnalyLine[LeftEdge-1]==NOSTONE)

    //左边有气

    if(LeftEdge>1 && AnalyLine[LeftEdge-2]==AnalyLine[LeftEdge])

    {

    //左边隔一空白有己方棋子

    m_LineRecord[LeftEdge]=SFOUR;//冲四

    m_LineRecord[LeftEdge-2]=ANALSISED;

    }

    else

    LeftThree=true;

    if(RightEdge

    if(AnalyLine[RightEdge+1]==NOSTONE)

    //右边有气

    if(RightEdge

    {

    //右边隔1个己方棋子

    m_LineRecord[RightEdge]=SFOUR;//冲四

    m_LineRecord[RightEdge+2]=ANALSISED;

    }

    else

    if(LeftThree==true)//如左边有气

    m_LineRecord[RightEdge]=THREE;//活三

    else

    m_LineRecord[RightEdge]=STHREE;//冲三

    else

    {

    if(m_LineRecord[LeftEdge]==SFOUR)//如左冲四

    returnm_LineRecord[LeftEdge];//返回

    if(LeftThree==true)//如左边有气

    m_LineRecord[nAnalyPos]=STHREE;//眠三

    }

    else

    {

    if(m_LineRecord[LeftEdge]==SFOUR)//如左冲四

    returnm_LineRecord[LeftEdge];//返回

    if(LeftThree==true)//如左边有气

    m_LineRecord[nAnalyPos]=STHREE;//眠三

    }

    returnm_LineRecord[nAnalyPos];

    }

    if(RightEdge-LeftEdge==1)

    {

    //如待分析棋子棋型为二连

    boolLefttwo=false;

    boolLeftthree=false;

    if(LeftEdge>2)

    if(AnalyLine[LeftEdge-1]==NOSTONE)

    //左边有气

    if(LeftEdge-1>1 && AnalyLine[LeftEdge-2]==AnalyLine[LeftEdge])

    if(AnalyLine[LeftEdge-3]==AnalyLine[LeftEdge])

    {

    //左边隔2个己方棋子

    m_LineRecord[LeftEdge-3]=ANALSISED;

    m_LineRecord[LeftEdge-2]=ANALSISED;

    m_LineRecord[LeftEdge]=SFOUR;//冲四

    }

    else

    if(AnalyLine[LeftEdge-3]==NOSTONE)

    {

    //左边隔1个己方棋子

    m_LineRecord[LeftEdge-2]=ANALSISED;

    m_LineRecord[LeftEdge]=STHREE;//眠三

    }

    else

    Lefttwo=true;

    if(RightEdge

    if(AnalyLine[RightEdge+1]==NOSTONE)

    //右边有气

    if(RightEdge+1

    if(AnalyLine[RightEdge+3]==AnalyLine[RightEdge])

    {

    //右边隔两个己方棋子

    m_LineRecord[RightEdge+3]=ANALSISED;

    m_LineRecord[RightEdge+2]=ANALSISED;

    m_LineRecord[RightEdge]=SFOUR;//冲四

    }

    else

    if(AnalyLine[RightEdge+3]==NOSTONE)

    {

    //右边隔 1 个己方棋子

    m_LineRecord[RightEdge+2]=ANALSISED;

    m_LineRecord[RightEdge]=STHREE;//眠三

    }

    else

    {

    if(m_LineRecord[LeftEdge]==SFOUR)//左边冲四

    returnm_LineRecord[LeftEdge];//返回

    if(m_LineRecord[LeftEdge]==STHREE)//左边眠三

    returnm_LineRecord[LeftEdge];

    if(Lefttwo==true)

    m_LineRecord[nAnalyPos]=TWO;//返回活二

    else

    m_LineRecord[nAnalyPos]=STWO;//眠二

    }

    else

    {

    if(m_LineRecord[LeftEdge]==SFOUR)//冲四返回

    returnm_LineRecord[LeftEdge];

    if(Lefttwo==true)//眠二

    m_LineRecord[nAnalyPos]=STWO;

    }

    returnm_LineRecord[nAnalyPos];

    }

    return0;

    }

    //将历史记录表中所有项目全置为初值

    voidResetHistoryTable()

    {

    memset(m_HistoryTable,10,GRID_COUNT*sizeof(int));

    }

    //从历史得分表中取给定走法的历史得分

    intGetHistoryScore(STONEMOVE* move)

    {

    returnm_HistoryTable[move->StonePos.x][move->StonePos.y];

    }

    //将一最佳走法汇入历史记录

    voidEnterHistoryScore(STONEMOVE* move,intdepth)

    {

    m_HistoryTable[move->StonePos.x][move->StonePos.y]+=2<

    }

    //对走法队列从小到大排序

    //STONEMOVE* source原始队列

    //STONEMOVE* target目标队列

    //合并source[l…m]和 source[m +1…r]至target[l…r]

    voidMerge(STONEMOVE* source,STONEMOVE* target,intl,intm,intr)

    {

    //从小到大排序

    inti=l;

    intj=m+1;

    intk=l;

    while(i<=m && j<=r)

    if(source[i].Score<=source[j].Score)

    target[k++]=source[i++];

    else

    target[k++]=source[j++];

    if(i>m)

    for(intq=j;q<=r;q++)

    target[k++]=source[q];

    else

    for(intq=i;q<=m;q++)

    target[k++]=source[q];

    }

    voidMerge_A(STONEMOVE* source,STONEMOVE* target,intl,intm,intr)

    {

    //从大到小排序

    inti=l;

    intj=m+1;

    intk=l;

    while(i<=m &&j<=r)

    if(source[i].Score>=source[j].Score)

    target[k++]=source[i++];

    else

    target[k++]=source[j++];

    if(i>m)

    for(intq=j;q<=r;q++)

    target[k++]=source[q];

    else

    for(intq=i;q<=m;q++)

    target[k++]=source[q];

    }

    //合并大小为 S 的相邻子数组

    //direction 是标志,指明是从大到小还是从小到大排序

    voidMergePass(STONEMOVE* source,STONEMOVE* target,constints,constintn,constbooldirection)

    {

    inti=0;

    while(i<=n-2*s)

    {

    //合并大小为 s的相邻二段子数组

    if(direction)

    Merge(source,target,i,i+s-1,i+2*s-1);

    else

    Merge_A(source,target,i,i+s-1,i+2*s-1);

    i=i+2*s;

    }

    if(i+s

    {

    if(direction)

    Merge(source,target,i,i+s-1,n-1);

    else

    Merge_A(source,target,i,i+s-1,n-1);

    }

    else

    for(intj=i;j<=n-1;j++)

    target[j]=source[j];

    }

    voidMergeSort(STONEMOVE* source,intn,booldirection)

    {

    ints=1;

    while(s

    {

    MergePass(source,m_TargetBuff,s,n,direction);

    s+=s;

    MergePass(m_TargetBuff,source,s,n,direction);

    s+=s;

    }

    }

    intCreatePossibleMove(unsignedcharposition[][GRID_NUM],intnPly,intnSide)

    {

    inti,j;

    m_nMoveCount=0;

    for(i=0;i

    for(j=0;j

    {

    if(position[i][j]==(unsignedchar)NOSTONE)

    AddMove(j,i,nPly);

    }

    //使用历史启发类中的静态归并排序函数对走法队列进行排序

    //这是为了提高剪枝效率

    //  CHistoryHeuristic history;

    MergeSort(m_MoveList[nPly],m_nMoveCount,0);

    returnm_nMoveCount;//返回合法走法个数

    }

    //在m_MoveList中插入一个走法

    //nToX是目标位置横坐标

    //nToY是目标位置纵坐标

    //nPly是此走法所在的层次

    intAddMove(intnToX,intnToY,intnPly)

    {

    m_MoveList[nPly][m_nMoveCount].StonePos.x=nToX;

    m_MoveList[nPly][m_nMoveCount].StonePos.y=nToY;

    m_nMoveCount++;

    m_MoveList[nPly][m_nMoveCount].Score=PosValue[nToY][nToX];//使用位置价值表评估当前走法的价值

    returnm_nMoveCount;

    }

    voidCNegaScout_TT_HH()

    {

    ResetHistoryTable();

    //  m_pThinkProgress=NULL;

    }

    voidSearchAGoodMove(unsignedcharposition[][GRID_NUM],intType)

    {

    intScore;

    memcpy(CurPosition,position,GRID_COUNT);

    m_nMaxDepth=m_nSearchDepth;

    CalculateInitHashKey(CurPosition);

    ResetHistoryTable();

    Score=NegaScout(m_nMaxDepth,-20000,20000);

    X=m_cmBestMove.StonePos.y;

    Y=m_cmBestMove.StonePos.x;

    MakeMove(&m_cmBestMove,Type);

    memcpy(position,CurPosition,GRID_COUNT);

    }

    intIsGameOver(unsignedcharposition[][GRID_NUM],intnDepth)

    {

    intscore,i;//计算要下的棋子颜色

    i=(m_nMaxDepth-nDepth)%2;

    score=Eveluate(position,i);//调用估值函数

    if(abs(score)>8000)//如果估值函数返回极值,给定局面游戏结束

    returnscore;//返回极值

    return0;//返回未结束

    }

    intNegaScout(intdepth,intalpha,intbeta)

    {

    intCount,i;

    unsignedchartype;

    inta,b,t;

    intside;

    intscore;

    /*  if(depth>0)

    {

    i= IsGameOver(CurPosition,depth);

    if(i!=0)

    return i;  //已分胜负,返回极值

    }

    */

    side=(m_nMaxDepth-depth)%2;//计算当前节点的类型,极大0/极小1

    score=LookUpHashTable(alpha,beta,depth,side);

    if(score!=66666)

    returnscore;

    if(depth<=0)//叶子节点取估值

    {

    score=Eveluate(CurPosition,side);

    EnterHashTable(exact,score,depth,side);//将估值存入置换表

    returnscore;

    }

    Count=CreatePossibleMove(CurPosition,depth,side);

    for(i=0;i

    m_MoveList[depth][i].Score=GetHistoryScore(&m_MoveList[depth][i]);

    MergeSort(m_MoveList[depth],Count,0);

    intbestmove=-1;

    a=alpha;

    b=beta;

    inteval_is_exact=0;

    for(i=0;i

    {

    type=MakeMove(&m_MoveList[depth][i],side);

    Hash_MakeMove(&m_MoveList[depth][i],CurPosition);

    t=-NegaScout(depth-1,-b,-a);//递归搜索子节点,对第 1 个节点是全窗口,其后是空窗探测

    if(t>a && t0)

    {

    //对于第一个后的节点,如果上面的搜索failhigh

    a=-NegaScout(depth-1,-beta,-t);//re-search

    eval_is_exact=1;//设数据类型为精确值

    if(depth==m_nMaxDepth)

    m_cmBestMove=m_MoveList[depth][i];

    bestmove=i;

    }

    Hash_UnMakeMove(&m_MoveList[depth][i],CurPosition);

    UnMakeMove(&m_MoveList[depth][i]);

    if(a

    {

    eval_is_exact=1;

    a=t;

    if(depth==m_nMaxDepth)

    m_cmBestMove=m_MoveList[depth][i];

    }

    if(a>= beta)

    {

    EnterHashTable(lower_bound,a,depth,side);

    EnterHistoryScore(&m_MoveList[depth][i],depth);

    returna;

    }

    b=a+1;/* set new null window */

    }

    if(bestmove!=-1)

    EnterHistoryScore(&m_MoveList[depth][bestmove], depth);

    if(eval_is_exact)

    EnterHashTable(exact,a,depth,side);

    else

    EnterHashTable(upper_bound,a,depth,side);

    returna;

    }

    unsignedcharMakeMove(STONEMOVE* move,inttype)

    {

    CurPosition[move->StonePos.y][move->StonePos.x]=type;

    return0;

    }

    voidUnMakeMove(STONEMOVE* move)

    {

    CurPosition[move->StonePos.y][move->StonePos.x]=NOSTONE;

    }

    __int64rand64(void)

    {

    returnrand()^((__int64)rand()<<15)^((__int64)rand()<<30)^

    ((__int64)rand()<<45)^((__int64)rand()<<60);

    }

    //生成32位随机数

    longrand32(void)

    {

    returnrand()^((long)rand()<<15)^((long)rand()<<30);

    }

    voidCTranspositionTable()

    {

    InitializeHashKey();//建立哈希表,创建随机数组

    }

    void_CTranspositionTable()

    {

    //释放哈希表所用空间

    deletem_pTT[0];

    deletem_pTT[1];

    }

    voidCalculateInitHashKey(unsignedcharCurPosition[][GRID_NUM])

    {

    intj,k,nStoneType;

    m_HashKey32=0;

    m_HashKey32=0;

    //将所有棋子对应的哈希数加总

    for(j=0;j

    for(k=0;k

    {

    nStoneType=CurPosition[j][k];

    if(nStoneType!=0xFF)

    {

    m_HashKey32=m_HashKey32^m_nHashKey32[nStoneType][j][k];

    m_HashKey64=m_HashKey64^m_ulHashKey64[nStoneType][j][k];

    }

    }

    }

    voidHash_MakeMove(STONEMOVE *move,unsignedcharCurPosition[][GRID_NUM])

    {

    inttype;

    type=CurPosition[move->StonePos.y][move->StonePos.x];//将棋子在目标位置的随机数添入

    m_HashKey32=m_HashKey32^m_nHashKey32[type][move->StonePos.y][move->StonePos.x];

    m_HashKey64=m_HashKey64^m_ulHashKey64[type][move->StonePos.y][move->StonePos.x];

    }

    voidHash_UnMakeMove(STONEMOVE *move,unsignedcharCurPosition[][GRID_NUM])

    {

    inttype;

    type=CurPosition[move->StonePos.y][move->StonePos.x];//将棋子现在位置上的随机数从哈希值当中去除

    m_HashKey32=m_HashKey32^m_nHashKey32[type][move->StonePos.y][move->StonePos.x];

    m_HashKey64=m_HashKey64^m_ulHashKey64[type][move->StonePos.y][move->StonePos.x];

    }

    intLookUpHashTable(intalpha,intbeta,intdepth,intTableNo)

    {

    intx;

    HashItem* pht;

    //计算二十位哈希地址,如果读者设定的哈希表大小不是 1M*2 的,

    //而是 TableSize*2,TableSize为读者设定的大小

    //则需要修改这一句为m_HashKey32% TableSize

    //下一个函数中这一句也一样

    x=m_HashKey32 & 0xFFFFF;

    pht=&m_pTT[TableNo][x];//取到具体的表项指针

    if(pht->depth>=depth && pht->checksum==m_HashKey64)

    {

    switch(pht->entry_type)//判断数据类型

    {

    caseexact://确切值

    returnpht->eval;

    caselower_bound://下边界

    if(pht->eval>=beta)

    returnpht->eval;

    else

    break;

    caseupper_bound://上边界

    if(pht->eval<=alpha)

    returnpht->eval;

    else

    break;

    }

    }

    return66666;

    }

    voidEnterHashTable(ENTRY_TYPE entry_type,shorteval,shortdepth,intTableNo)

    {

    intx;

    HashItem* pht;

    x=m_HashKey32 & 0xFFFFF;//计算二十位哈希地址

    pht=&m_pTT[TableNo][x];//取到具体的表项指针

    //将数据写入哈希表

    pht->checksum=m_HashKey64;//64位校验码

    pht->entry_type=entry_type;//表项类型

    pht->eval=eval;//要保存的值

    pht->depth=depth;//层次

    }

    voidInitializeHashKey()

    {

    inti,j,k;

    srand((unsigned)time(NULL));

    //填充随机数组

    for(i=0;i<15;i++)

    for(j=0;j<10;j++)

    for(k=0;k<9;k++)

    {

    m_nHashKey32[i][j][k]=rand32();

    m_ulHashKey64[i][j][k]=rand64();

    }

    //申请置换表所用空间。1M "2 个条目,读者也可指定其他大小

    m_pTT[0]=newHashItem[1024*1024];//用于存放取极大值的节点数据

    m_pTT[1]=newHashItem[1024*1024];//用于存放取极小值的节点数据

    }

    intmain()

    {

    intcolour;

    charcommand[10];//用于保存命令的字符串

    for(inti = 0; i < GRID_NUM; i++)

    for(intj = 0; j < GRID_NUM; j++)

    m_RenjuBoard[i][j] = NOSTONE;//棋盘初始化

    cin >> command;

    if(strcmp(command,"[START]") != 0)//读入第一条命令

    {

    return0;//如果不是[START]则停止程序

    }

    cin >> colour;//读入己方颜色

    colour=colour-1;

    m_nUserStoneColor=1-colour;

    while(true)

    {

    intrival_x, rival_y;//用于保存对手上一步落子点

    cin >> command;//读入命令

    if(strcmp(command,"[PUT]") != 0)

    break;//如果不是[PUT]则停止程序

    cin >> rival_x >> rival_y;//读入对手上一步落子点

    if(colour == 0 && rival_x == -1 && rival_y == -1)//如果己方执黑且是第一步,则占据棋盘中心位置

    {

    m_RenjuBoard[GRID_NUM / 2][GRID_NUM / 2] = colour;//更新棋盘信息

    cout << GRID_NUM / 2 <<' '<< GRID_NUM / 2 << endl;//输出

    cout << flush;//刷新缓冲区

    }

    else

    {

    m_RenjuBoard[rival_x][rival_y] = 1 - colour;

    //更新棋盘信息

    m_nSearchDepth=3;

    //最大搜索深度

    do

    {

    CNegaScout_TT_HH();//创建NegaScout_TT_HH搜索引擎

    CTranspositionTable();

    SearchAGoodMove(m_RenjuBoard,colour);

    m_RenjuBoard[X][Y]=colour;

    cout << X <<' '<< Y << endl;//输出

    cout << flush;//刷新缓冲区

    _CTranspositionTable();

    break;//结束循环

    }

    while(true);

    //循环直至随机得到一个空位置

    }

    }

    return0;

    }

    相关文章

      网友评论

          本文标题:五子棋人机对弈代码——之博弈树算法

          本文链接:https://www.haomeiwen.com/subject/ghnaattx.html