Fichiers repris sans modification dans engine/gnubg/, poids et table d'équité Kazaross-XG2 dans engine/data/, provenance détaillée dans engine/gnubg/PROVENANCE.md. Le lint ne vérifie plus les espaces de ces copies, pour qu'elles restent identiques à l'original. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
284 lines
6.9 KiB
C
284 lines
6.9 KiB
C
/*
|
|
* Copyright (C) 2002-2003 Joern Thyssen <jthyssen@dk.ibm.com>
|
|
* Copyright (C) 2004-2013 the AUTHORS
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* $Id: matchid.c,v 1.30 2021/12/18 22:06:37 plm Exp $
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "backgammon.h"
|
|
#include "positionid.h"
|
|
#include "matchequity.h"
|
|
#include "matchid.h"
|
|
#include <string.h>
|
|
|
|
/*
|
|
* Calculate log2 of Cube value.
|
|
*
|
|
* Input:
|
|
* n: cube value
|
|
*
|
|
* Returns:
|
|
* log(n)/log(2)
|
|
*
|
|
*/
|
|
|
|
extern int
|
|
LogCube(int n)
|
|
{
|
|
int i = 0;
|
|
|
|
while (n >>= 1)
|
|
i++;
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
static void
|
|
SetBit(unsigned char *pc, unsigned int bitPos, int test, unsigned int iBit)
|
|
{
|
|
|
|
const unsigned int k = bitPos / 8;
|
|
const unsigned char rbit = (unsigned char) (0x1 << (bitPos % 8));
|
|
|
|
unsigned char c;
|
|
|
|
if (test & (0x1 << iBit))
|
|
c = rbit;
|
|
else
|
|
c = 0;
|
|
pc[k] = (pc[k] & (0xFF ^ rbit)) | c;
|
|
|
|
}
|
|
|
|
static void
|
|
SetBits(unsigned char *pc, unsigned int bitPos, unsigned int nBits, int iContent)
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
/* FIXME: rewrite SetBit, SetBits to be faster */
|
|
|
|
|
|
for (i = 0; i < nBits; i++) {
|
|
|
|
SetBit(pc, bitPos + i, iContent, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
GetBits(const unsigned char *pc, const unsigned int bitPos, const unsigned int nBits, int *piContent)
|
|
{
|
|
unsigned int i, j;
|
|
unsigned char c[2];
|
|
|
|
/* FIXME: rewrite GetBits to be faster */
|
|
|
|
c[0] = 0;
|
|
c[1] = 0;
|
|
|
|
for (i = 0, j = bitPos; i < nBits; i++, j++) {
|
|
|
|
unsigned int k, r;
|
|
|
|
k = j / 8;
|
|
r = j % 8;
|
|
|
|
SetBit(c, i, pc[k], r);
|
|
|
|
}
|
|
|
|
*piContent = c[0] | (c[1] << 8);
|
|
}
|
|
|
|
|
|
static char *
|
|
MatchIDFromKey(unsigned char auchKey[9])
|
|
{
|
|
unsigned char *puch = auchKey;
|
|
static char szID[L_MATCHID + 1];
|
|
char *pch = szID;
|
|
static const char aszBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
*pch++ = aszBase64[puch[0] >> 2];
|
|
*pch++ = aszBase64[((puch[0] & 0x03) << 4) | (puch[1] >> 4)];
|
|
*pch++ = aszBase64[((puch[1] & 0x0F) << 2) | (puch[2] >> 6)];
|
|
*pch++ = aszBase64[puch[2] & 0x3F];
|
|
|
|
puch += 3;
|
|
}
|
|
|
|
*pch = 0;
|
|
|
|
return szID;
|
|
}
|
|
|
|
|
|
extern char *
|
|
MatchID(const unsigned int anDice[2],
|
|
const int fTurn,
|
|
const int fResigned,
|
|
const int fDoubled,
|
|
const int fMove,
|
|
const int fCubeOwner, const int fCrawford, const int nMatchTo, const int anScore[2], const int nCube,
|
|
const int fJacobyInUse, const gamestate gs)
|
|
{
|
|
|
|
unsigned char auchKey[9];
|
|
|
|
memset(auchKey, 0, 9);
|
|
|
|
SetBits(auchKey, 0, 4, LogCube(nCube));
|
|
SetBits(auchKey, 4, 2, fCubeOwner & 0x3);
|
|
SetBits(auchKey, 6, 1, fMove);
|
|
SetBits(auchKey, 7, 1, fCrawford);
|
|
SetBits(auchKey, 8, 3, (int) gs);
|
|
SetBits(auchKey, 11, 1, fTurn);
|
|
SetBits(auchKey, 12, 1, fDoubled);
|
|
SetBits(auchKey, 13, 2, fResigned);
|
|
if (anDice[0] >= anDice[1]) {
|
|
SetBits(auchKey, 15, 3, anDice[0] & 0x7);
|
|
SetBits(auchKey, 18, 3, anDice[1] & 0x7);
|
|
} else {
|
|
SetBits(auchKey, 15, 3, anDice[1] & 0x7);
|
|
SetBits(auchKey, 18, 3, anDice[0] & 0x7);
|
|
}
|
|
SetBits(auchKey, 21, 15, nMatchTo & 0x7FFF);
|
|
SetBits(auchKey, 36, 15, anScore[0] & 0x7FFF);
|
|
SetBits(auchKey, 51, 15, anScore[1] & 0x7FFF);
|
|
SetBits(auchKey, 66, 1, (!fJacobyInUse));
|
|
|
|
return MatchIDFromKey(auchKey);
|
|
|
|
}
|
|
|
|
static int
|
|
MatchFromKey(int anDice[2],
|
|
int *pfTurn,
|
|
int *pfResigned,
|
|
int *pfDoubled,
|
|
int *pfMove, int *pfCubeOwner, int *pfCrawford, int *pnMatchTo, int anScore[2], int *pnCube,
|
|
int *pfJacoby, gamestate * pgs, const unsigned char *auchKey)
|
|
{
|
|
int temp;
|
|
GetBits(auchKey, 0, 4, pnCube);
|
|
*pnCube = 0x1 << *pnCube;
|
|
|
|
GetBits(auchKey, 4, 2, pfCubeOwner);
|
|
if (*pfCubeOwner && *pfCubeOwner != 1)
|
|
*pfCubeOwner = -1;
|
|
|
|
GetBits(auchKey, 6, 1, pfMove);
|
|
GetBits(auchKey, 7, 1, pfCrawford);
|
|
GetBits(auchKey, 8, 3, &temp);
|
|
*pgs = (gamestate) temp;
|
|
GetBits(auchKey, 11, 1, pfTurn);
|
|
GetBits(auchKey, 12, 1, pfDoubled);
|
|
GetBits(auchKey, 13, 2, pfResigned);
|
|
GetBits(auchKey, 15, 3, &anDice[0]);
|
|
GetBits(auchKey, 18, 3, &anDice[1]);
|
|
GetBits(auchKey, 21, 15, pnMatchTo);
|
|
GetBits(auchKey, 36, 15, &anScore[0]);
|
|
GetBits(auchKey, 51, 15, &anScore[1]);
|
|
GetBits(auchKey, 66, 1, pfJacoby);
|
|
*pfJacoby = !(*pfJacoby);
|
|
|
|
/* FIXME: implement a consistency check */
|
|
|
|
if (anDice[0] < 0 || anDice[0] > 6)
|
|
return -1;
|
|
if (anDice[1] < 0 || anDice[1] > 6)
|
|
return -1;
|
|
if (*pnMatchTo < 0 || *pnMatchTo > MAXSCORE)
|
|
return -1;
|
|
|
|
if (*pnMatchTo) {
|
|
if (anScore[0] < 0 || anScore[0] > *pnMatchTo)
|
|
return -1;
|
|
if (anScore[1] < 0 || anScore[1] > *pnMatchTo)
|
|
return -1;
|
|
} else {
|
|
/* money game */
|
|
if (*pfCrawford)
|
|
/* no Crawford game in money play */
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
extern int
|
|
MatchFromID(unsigned int anDice[2],
|
|
int *pfTurn,
|
|
int *pfResigned,
|
|
int *pfDoubled, int *pfMove, int *pfCubeOwner, int *pfCrawford, int *pnMatchTo, int anScore[2], int *pnCube,
|
|
int *pfJacoby, gamestate * pgs, const char *szMatchID)
|
|
{
|
|
|
|
unsigned char auchKey[9];
|
|
unsigned char *puch = auchKey;
|
|
unsigned char ach[L_MATCHID + 1];
|
|
unsigned char *pch = ach;
|
|
int i;
|
|
|
|
memset(ach, 0, sizeof(ach));
|
|
/* decode base64 into key */
|
|
for (i = 0; i < L_MATCHID && szMatchID[i]; i++)
|
|
pch[i] = Base64((unsigned char) szMatchID[i]);
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
*puch++ = (unsigned char) (pch[0] << 2) | (pch[1] >> 4);
|
|
*puch++ = (unsigned char) (pch[1] << 4) | (pch[2] >> 2);
|
|
*puch++ = (unsigned char) (pch[2] << 6) | pch[3];
|
|
|
|
pch += 4;
|
|
}
|
|
|
|
/* get matchstate info from the key */
|
|
|
|
return MatchFromKey((int *) anDice, pfTurn, pfResigned, pfDoubled, pfMove, pfCubeOwner, pfCrawford, pnMatchTo,
|
|
(int *) anScore, pnCube, pfJacoby, pgs, auchKey);
|
|
}
|
|
|
|
/*
|
|
* Generate match ID from matchstate
|
|
*
|
|
* Input:
|
|
* pms: match state
|
|
*
|
|
*/
|
|
|
|
extern char *
|
|
MatchIDFromMatchState(const matchstate * pms)
|
|
{
|
|
|
|
return MatchID(pms->anDice,
|
|
pms->fTurn,
|
|
pms->fResigned,
|
|
pms->fDoubled, pms->fMove, pms->fCubeOwner, pms->fCrawford, pms->nMatchTo, pms->anScore, pms->nCube,
|
|
pms->fJacoby, pms->gs);
|
|
|
|
}
|