static void
BearOff(int nId, unsigned int nPoints,
        unsigned short int aOutProb[64],
        const int fGammon, xhash * ph, bearoffcontext * pbc, const int fCompress, FILE * pfOutput, FILE * pfTmp)
{
#if !defined(G_DISABLE_ASSERT)
    int iBest;
#endif
    int iMode, j, anRoll[2], aProb[64];
    unsigned int i;
    TanBoard anBoard, anBoardTemp;
    movelist ml;
    int k;
    unsigned int us;
    unsigned int usBest;
    unsigned short int *pusj;
    unsigned short int ausj[64];
    unsigned short int ausBest[32];

    unsigned int usGammonBest;
    unsigned short int ausGammonBest[32];
    unsigned int nBack;

    /* get board for given position */

    PositionFromBearoff(anBoard[1], nId, nPoints, 15);

    /* initialise probabilities */

    for (i = 0; i < 64; i++)
        aProb[i] = aOutProb[i] = 0;

    /* all chequers off is easy :-) */

    if (!nId) {
        aOutProb[0] = 0xFFFF;
        aOutProb[32] = 0xFFFF;
        return;
    }

    /* initialise the remainder of the board */

    for (i = nPoints; i < 25; i++)
        anBoard[1][i] = 0;

    for (i = 0; i < 25; i++)
        anBoard[0][i] = 0;

    nBack = 0;
    for (i = 0, k = 0; i < nPoints; ++i) {
        if (anBoard[1][i])
            nBack = i;
        k += anBoard[1][i];
    }

    /* look for position in existing bearoff file */

    if (pbc && nBack < pbc->nPoints) {
        unsigned int nPosID = PositionBearoff(anBoard[1],
                                              pbc->nPoints, pbc->nChequers);
        BearoffDist(pbc, nPosID, NULL, NULL, NULL, aOutProb, aOutProb + 32);
        return;
    }

    if (k < 15)
        aProb[32] = 0xFFFF * 36;

    for (anRoll[0] = 1; anRoll[0] <= 6; anRoll[0]++)
        for (anRoll[1] = 1; anRoll[1] <= anRoll[0]; anRoll[1]++) {
            GenerateMoves(&ml, (ConstTanBoard) anBoard, anRoll[0], anRoll[1], FALSE);

            usBest = 0xFFFFFFFF;
#if !defined(G_DISABLE_ASSERT)
            iBest = -1;
#endif
            usGammonBest = 0xFFFFFFFF;

            for (i = 0; i < ml.cMoves; i++) {
                PositionFromKey(anBoardTemp, &ml.amMoves[i].key);

                j = PositionBearoff(anBoardTemp[1], nPoints, 15);

                g_assert(j >= 0);
                g_assert(j < nId);


                if (!j) {

                    memset(pusj = ausj, 0, fGammon ? 128 : 64);
                    pusj[0] = 0xFFFF;
                    pusj[32] = 0xFFFF;

                } else if (!(pusj = XhashLookup(ph, j))) {
                    /* look up in file generated so far */
                    pusj = ausj;
                    OSLookup(j, nPoints, pusj, fGammon, fCompress, pfOutput, pfTmp);

                    XhashAdd(ph, j, pusj, fGammon ? 128 : 64);
                }

                /* find best move to win */

                if ((us = RollsOS(pusj)) < usBest) {
#if !defined(G_DISABLE_ASSERT)
                    iBest = j;
#endif
                    usBest = us;
                    memcpy(ausBest, pusj, 64);
                }

                /* find best move to save gammon */

                if (fGammon && ((us = RollsOS(pusj + 32)) < usGammonBest)) {
                    usGammonBest = us;
                    memcpy(ausGammonBest, pusj + 32, 64);
                }

            }

            g_assert(iBest >= 0);
            /* g_assert( iGammonBest >= 0 ); */

            if (anRoll[0] == anRoll[1]) {
                for (i = 0; i < 31; i++) {
                    aProb[i + 1] += ausBest[i];
                    if (k == 15 && fGammon)
                        aProb[32 + i + 1] += ausGammonBest[i];
                }
            } else {
                for (i = 0; i < 31; i++) {
                    aProb[i + 1] += 2 * ausBest[i];
                    if (k == 15 && fGammon)
                        aProb[32 + i + 1] += 2 * ausGammonBest[i];
                }
            }
        }

    for (i = 0, j = 0, iMode = 0; i < 32; i++) {
        j += (aOutProb[i] = (unsigned short) ((aProb[i] + 18) / 36));
        if (aOutProb[i] > aOutProb[iMode])
            iMode = i;
    }

    aOutProb[iMode] -= (j - 0xFFFF);

    /* gammon probs */

    if (fGammon) {
        for (i = 0, j = 0, iMode = 0; i < 32; i++) {
            j += (aOutProb[32 + i] = (unsigned short) ((aProb[32 + i] + 18) / 36));
            if (aOutProb[32 + i] > aOutProb[32 + iMode])
                iMode = i;
        }

        aOutProb[32 + iMode] -= (j - 0xFFFF);
    }

}
Example #2
0
static void
NDBearoff(const int iPos, const unsigned int nPoints, float ar[4], xhash * ph, bearoffcontext * pbc)
{

    int d0, d1;
    movelist ml;
    TanBoard anBoard, anBoardTemp;
    int ii, j, k;
    unsigned int i;
#if !defined(G_DISABLE_ASSERT)
    int iBest;
    int iGammonBest;
#endif
    float rBest;
    float rMean;
    float rVarSum, rGammonVarSum;
    float *prj;
    float arj[4] = { 0.0, 0.0, 0.0, 0.0 };
    float arBest[4] = { 0.0, 0.0, 0.0, 0.0 };
    float arGammonBest[4] = { 0.0, 0.0, 0.0, 0.0 };
    float rGammonBest;

    for (i = 0; i < 4; ++i)
        ar[i] = 0.0f;

    if (!iPos)
        return;

    PositionFromBearoff(anBoard[1], iPos, nPoints, 15);

    for (i = nPoints; i < 25; i++)
        anBoard[1][i] = 0;

    /* 
     * look for position in existing bearoff file 
     */

    if (pbc) {
        for (ii = 24; ii >= 0 && !anBoard[1][ii]; --ii);

        if (ii < (int) pbc->nPoints) {
            unsigned int nPosID = PositionBearoff(anBoard[1],
                                                  pbc->nPoints, pbc->nChequers);
            BearoffDist(pbc, nPosID, NULL, NULL, ar, NULL, NULL);
            return;
        }

    }

    memset(anBoard[0], 0, 25 * sizeof(int));

    for (i = 0, k = 0; i < nPoints; ++i)
        k += anBoard[1][i];

    /* loop over rolls */

    rVarSum = rGammonVarSum = 0.0f;

    for (d0 = 1; d0 <= 6; ++d0)
        for (d1 = 1; d1 <= d0; ++d1) {

            GenerateMoves(&ml, (ConstTanBoard) anBoard, d0, d1, FALSE);

            rBest = 1e10;
            rGammonBest = 1e10;
#if !defined(G_DISABLE_ASSERT)
            iBest = -1;
            iGammonBest = -1;
#endif

            for (i = 0; i < ml.cMoves; ++i) {

                PositionFromKey(anBoardTemp, &ml.amMoves[i].key);

                j = PositionBearoff(anBoardTemp[1], nPoints, 15);

                if (!(prj = XhashLookup(ph, j))) {
                    prj = arj;
                    NDBearoff(j, nPoints, prj, ph, pbc);
                    XhashAdd(ph, j, prj, 16);
                }

                /* find best move to win */

                if (prj[0] < rBest) {
#if !defined(G_DISABLE_ASSERT)
                    iBest = j;
#endif
                    rBest = prj[0];
                    memcpy(arBest, prj, 4 * sizeof(float));
                }

                /* find best move to save gammon */

                if (prj[2] < rGammonBest) {
#if !defined(G_DISABLE_ASSERT)
                    iGammonBest = j;
#endif
                    rGammonBest = prj[2];
                    memcpy(arGammonBest, prj, 4 * sizeof(float));
                }

            }

            g_assert(iBest >= 0);
            g_assert(iGammonBest >= 0);

            rMean = 1.0f + arBest[0];

            ar[0] += (d0 == d1) ? rMean : 2.0f * rMean;

            rMean = arBest[1] * arBest[1] + rMean * rMean;

            rVarSum += (d0 == d1) ? rMean : 2.0f * rMean;

            if (k == 15) {

                rMean = 1.0f + arGammonBest[2];

                ar[2] += (d0 == d1) ? rMean : 2.0f * rMean;

                rMean = arGammonBest[3] * arGammonBest[3] + rMean * rMean;

                rGammonVarSum += (d0 == d1) ? rMean : 2.0f * rMean;

            }

        }


    ar[0] /= 36.0f;
    ar[1] = sqrt(rVarSum / 36.0f - ar[0] * ar[0]);

    ar[2] /= 36.0f;
    ar[3] = sqrt(rGammonVarSum / 36.0f - ar[2] * ar[2]);

}
Example #3
0
static void
BearOff2(int nUs, int nThem,
         const int nTSP, const int nTSC,
         short int asiEquity[4], const int n, const int fCubeful, xhash * ph, bearoffcontext * pbc, FILE * pfTmp)
{

    int j, anRoll[2];
    unsigned int i;
    TanBoard anBoard, anBoardTemp;
    movelist ml;
    int aiBest[4];
    int asiBest[4];
    int aiTotal[4];
    short int k;
    short int *psij;
    short int asij[4];
    const short int EQUITY_P1 = 0x7FFF;
    const short int EQUITY_M1 = ~EQUITY_P1;

    if (!nUs) {

        /* we have won */
        asiEquity[0] = asiEquity[1] = asiEquity[2] = asiEquity[3] = EQUITY_P1;
        return;

    }

    if (!nThem) {

        /* we have lost */
        asiEquity[0] = asiEquity[1] = asiEquity[2] = asiEquity[3] = EQUITY_M1;
        return;

    }

    PositionFromBearoff(anBoard[0], nThem, nTSP, nTSC);
    PositionFromBearoff(anBoard[1], nUs, nTSP, nTSC);

    for (i = nTSP; i < 25; i++)
        anBoard[1][i] = anBoard[0][i] = 0;

    /* look for position in bearoff file */

    if (pbc && isBearoff(pbc, (ConstTanBoard) anBoard)) {
        unsigned short int nUsL = PositionBearoff(anBoard[1], pbc->nPoints, pbc->nChequers);
        unsigned short int nThemL = PositionBearoff(anBoard[0], pbc->nPoints, pbc->nChequers);
        int nL = Combination(pbc->nPoints + pbc->nChequers, pbc->nPoints);
        unsigned int iPos = nUsL * nL + nThemL;
        unsigned short int aus[4];

        BearoffCubeful(pbc, iPos, NULL, aus);

        for (i = 0; i < 4; ++i)
            asiEquity[i] = aus[i] - 0x8000;

        return;
    }

    aiTotal[0] = aiTotal[1] = aiTotal[2] = aiTotal[3] = 0;

    for (anRoll[0] = 1; anRoll[0] <= 6; anRoll[0]++)
        for (anRoll[1] = 1; anRoll[1] <= anRoll[0]; anRoll[1]++) {
            GenerateMoves(&ml, (ConstTanBoard) anBoard, anRoll[0], anRoll[1], FALSE);

            asiBest[0] = asiBest[1] = asiBest[2] = asiBest[3] = -0xFFFF;
            aiBest[0] = aiBest[1] = aiBest[2] = aiBest[3] = -1;

            for (i = 0; i < ml.cMoves; i++) {
                PositionFromKey(anBoardTemp, &ml.amMoves[i].key);

                j = PositionBearoff(anBoardTemp[1], nTSP, nTSC);

                g_assert(j >= 0);
                g_assert(j < nUs);

                if (!nThem) {
                    asij[0] = asij[1] = asij[2] = asij[3] = EQUITY_P1;
                } else if (!j) {
                    asij[0] = asij[1] = asij[2] = asij[3] = EQUITY_M1;
                }
                if (!(psij = XhashLookup(ph, n * nThem + j))) {
                    /* lookup in file */
                    psij = asij;
                    TSLookup(nThem, j, nTSP, nTSC, psij, n, fCubeful, pfTmp);
                    XhashAdd(ph, n * nThem + j, psij, fCubeful ? 8 : 2);
                }

                /* cubeless */

                if (psij[0] < -asiBest[0]) {
                    aiBest[0] = j;
                    asiBest[0] = ~psij[0];
                }

                if (fCubeful) {

                    /* I own cube:
                     * from opponent's view he doesn't own cube */

                    if (psij[3] < -asiBest[1]) {
                        aiBest[1] = j;
                        asiBest[1] = ~psij[3];
                    }

                    /* Centered cube (so centered for opponent too) */

                    k = CubeEquity(psij[2], psij[3], EQUITY_P1);
                    if (~k > asiBest[2]) {
                        aiBest[2] = j;
                        asiBest[2] = ~k;
                    }

                    /* Opponent owns cube:
                     * from opponent's view he owns cube */

                    k = CubeEquity(psij[1], psij[3], EQUITY_P1);
                    if (~k > asiBest[3]) {
                        aiBest[3] = j;
                        asiBest[3] = ~k;
                    }

                }

            }

            g_assert(aiBest[0] >= 0);
            g_assert(!fCubeful || aiBest[1] >= 0);
            g_assert(!fCubeful || aiBest[2] >= 0);
            g_assert(!fCubeful || aiBest[3] >= 0);

            if (anRoll[0] == anRoll[1])
                for (k = 0; k < (fCubeful ? 4 : 1); ++k)
                    aiTotal[k] += asiBest[k];
            else
                for (k = 0; k < (fCubeful ? 4 : 1); ++k)
                    aiTotal[k] += 2 * asiBest[k];

        }

    /* final equities */
    for (k = 0; k < (fCubeful ? 4 : 1); ++k)
        asiEquity[k] = aiTotal[k] / 36;

}
static void
HyperEquity ( const int nUs, const int nThem,
              hyperequity *phe, const int nC, const hyperequity aheOld[],
              float arNorm[] ) {

  TanBoard anBoard;
  TanBoard anBoardTemp;
  movelist ml;
  int i, j;
  unsigned int k;
  int nUsNew, nThemNew;
  hyperequity heBest;
  hyperequity heOld;
  hyperequity heNew;
  int nPos = Combination ( 25 + nC, nC );
  const hyperequity *phex;
  float r;
  hyperclass hc;

  /* save old hyper equity */

  memcpy ( &heOld, phe, sizeof ( hyperequity ) );

  /* generate board for position */
  
  PositionFromBearoff ( anBoard[ 0 ], nThem, 25, nC );
  PositionFromBearoff ( anBoard[ 1 ], nUs, 25, nC );

  switch ( ( hc = ClassifyHyper ( anBoard ) ) ) {
  case HYPER_OVER:

    HyperOver ( (ConstTanBoard)anBoard, phe->arOutput, nC );

    for ( k = 0; k < 5; ++k )
      phe->arEquity[ k ] = Utility ( phe->arOutput, &ci );

    /* special calc for Jacoby rule */

    phe->arEquity[ EQUITY_CENTER_JACOBY ] = 
      Utility ( phe->arOutput, &ciJacoby );

    return;
    break;

  case HYPER_ILLEGAL:

    return;
    break;

  case HYPER_BEAROFF:
  case HYPER_CONTACT:

    for ( k = 0; k < NUM_OUTPUTS; ++k )
      heNew.arOutput[ k ] = 0.0f;
    for ( k = 0; k < 5; ++k )
      heNew.arEquity[ k ] = 0.0f;

    for ( i = 1; i <= 6; ++i ) 
      for ( j = 1; j <= i; ++j ) {
      
        GenerateMoves ( &ml, (ConstTanBoard)anBoard, i, j, FALSE );

        if ( ml.cMoves ) {

          /* at least one legal move: find the equity of the best move */

          for ( k = 0; k < 5; ++k )
            heBest.arEquity[ k ] = -10000.0f;
        
          for ( k = 0; k < ml.cMoves; ++k ) {
          
            PositionFromKey ( anBoardTemp, &ml.amMoves[ k ].key );
          
            nUsNew = PositionBearoff( anBoardTemp[ 1 ], 25, nC );
            nThemNew = PositionBearoff( anBoardTemp[ 0 ], 25, nC );
          
            g_assert ( nUsNew >= 0 );
            g_assert ( nUsNew < nUs );
            g_assert ( nThemNew >= 0 );

            /* cubeless */

            phex = &aheOld[ nPos * nThemNew + nUsNew ];

            r = - phex->arEquity[ EQUITY_CUBELESS ];
 
            if ( r >= heBest.arEquity[ EQUITY_CUBELESS ] ) {
              memcpy ( heBest.arOutput, phex->arOutput, 
                       NUM_OUTPUTS * sizeof ( float ) );
              InvertEvaluation ( heBest.arOutput );
              heBest.arEquity[ EQUITY_CUBELESS ] = r;
            }

            /* I own cube:
               from opponent's view he doesn't own cube */

            r = - phex->arEquity[ EQUITY_OPPONENT ];
          
            if ( r >= heBest.arEquity[ EQUITY_OWNED ] )
              heBest.arEquity[ EQUITY_OWNED ] = r;

            /* Centered cube, i.e., centered for opponent too */

            r = - CubeEquity ( phex->arEquity[ EQUITY_CENTER ],
                               phex->arEquity[ EQUITY_OPPONENT ],
                               +1.0 );
            
            if ( r >= heBest.arEquity[ EQUITY_CENTER ] )
              heBest.arEquity[ EQUITY_CENTER ] = r;

            /* centered cube with Jacoby rule */

            r = - CubeEquity ( phex->arEquity[ EQUITY_CENTER_JACOBY ],
                               phex->arEquity[ EQUITY_OPPONENT ],
                               +1.0 );
            
            if ( r >= heBest.arEquity[ EQUITY_CENTER_JACOBY ] )
              heBest.arEquity[ EQUITY_CENTER_JACOBY ] = r;

            /* Opponent owns cube: from opponent's view he owns cube */

            r = - CubeEquity ( phex->arEquity[ EQUITY_OWNED ],
                               phex->arEquity[ EQUITY_OPPONENT ],
                               +1.0 );

            if ( r >= heBest.arEquity[ EQUITY_OPPONENT ] )
              heBest.arEquity[ EQUITY_OPPONENT ] = r;

          }

        }
        else {

          /* no legal moves: equity is minus the equity of the reverse
             position, which has the opponent on roll */
          
          memcpy( &heBest, &aheOld[ nPos * nThem  + nUs ], 
                  sizeof ( hyperequity ) );

          InvertEvaluation ( heBest.arOutput );
          
          for ( k = 0; k < 5; ++k )
            heBest.arEquity[ k ] = - heBest.arEquity[ k ];

        }

        /* sum up equities */

        for ( k = 0; k < NUM_OUTPUTS; ++k )
          heNew.arOutput[ k ] += 
            ( i == j ) ? heBest.arOutput[ k ] : 2.0 * heBest.arOutput[ k ];
        for ( k = 0; k < 5; ++k )
          heNew.arEquity[ k ] += 
            ( i == j ) ? heBest.arEquity[ k ] : 2.0 * heBest.arEquity[ k ];

      }
  
    /* normalise */

    for ( k = 0; k < NUM_OUTPUTS; ++k )
      phe->arOutput[ k ] = heNew.arOutput[ k ] / 36.0;
    for ( k = 0; k < 5; ++k )
      phe->arEquity[ k ] = heNew.arEquity[ k ] / 36.0;

    break;

  }

  /* calculate contribution to norm */

  for ( k = 0; k < NUM_OUTPUTS; ++k ) {
    r = fabsf ( phe->arOutput[ k ] - heOld.arOutput[ k ] );
    if ( r > arNorm[ k ] ) {
       arNorm[ k ] = r;
       aiNorm[ k ] = nUs * nPos + nThem;
    }
  }
  for ( k = 0; k < 5; ++k ) {
    r = fabsf( phe->arEquity[ k ] - heOld.arEquity[ k ] );
    if ( r > arNorm[ 5 + k ] ) {
       arNorm[ 5 + k ] = r;
       aiNorm[ 5 + k ] = nUs * nPos + nThem;
    }
  }


}