Interface engine.h et programme engine-cli
engine.h expose initialisation, coups légaux, classement des coups, évaluation et décision de videau, avec Position ID et Match ID, sans type gnubg ; erreurs par code de retour. engine-cli l'interroge et répond en JSON (bestmove, moves, legal, cube, eval ; option --ply). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
42bfb6506d
commit
da5fa71ff8
+371
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* engine.c -- façade du moteur d'Ustagammon sur le cœur de GNU Backgammon.
|
||||
*
|
||||
* Copyright (C) 2026 les auteurs d'Ustagammon.
|
||||
* Licence : GPLv3 ou ultérieure (voir LICENSE).
|
||||
*
|
||||
* Chaque fonction décode les identifiants de position, prépare le contexte
|
||||
* de gnubg (cubeinfo, réglages d'évaluation) comme le fait gnubg de bureau
|
||||
* pour ses commandes « hint » et « eval », puis appelle gnubg.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "backgammon.h"
|
||||
#include "drawboard.h"
|
||||
#include "matchequity.h"
|
||||
#include "matchid.h"
|
||||
#include "multithread.h"
|
||||
#include "positionid.h"
|
||||
#include "gnubg-support.h"
|
||||
#include "engine.h"
|
||||
|
||||
/* Nombre de castors autorisés en partie libre : valeur par défaut de gnubg. */
|
||||
#define DEFAULT_BEAVERS 3
|
||||
|
||||
/* Fichier de table d'équité de match : celui de gnubg de bureau par défaut. */
|
||||
#define MET_FILE "Kazaross-XG2.xml"
|
||||
|
||||
/* gnubg ne sait pas se réinitialiser après EvalShutdown : on retient l'état. */
|
||||
static enum { NOT_STARTED, READY, STOPPED } engine_state = NOT_STARTED;
|
||||
|
||||
/* Une position décodée, prête pour gnubg. */
|
||||
typedef struct {
|
||||
TanBoard board;
|
||||
cubeinfo cube;
|
||||
engine_match match;
|
||||
} position;
|
||||
|
||||
/* -------------------------------------------------------- Initialisation */
|
||||
|
||||
/* Vérifie l'en-tête de gnubg.wd, pour éviter l'exit() de EvalInitialise. */
|
||||
static int
|
||||
binary_weights_ok(const char *path)
|
||||
{
|
||||
float header[2];
|
||||
FILE *f = fopen(path, "rb");
|
||||
int ok;
|
||||
|
||||
if (!f)
|
||||
return 0;
|
||||
ok = fread(header, sizeof header[0], 2, f) == 2
|
||||
&& header[0] == WEIGHTS_MAGIC_BINARY && header[1] == WEIGHTS_VERSION_BINARY;
|
||||
fclose(f);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static engine_status
|
||||
load_match_equity_table(const char *data_dir)
|
||||
{
|
||||
char *path = g_build_filename(data_dir, MET_FILE, NULL);
|
||||
int ok;
|
||||
|
||||
ok = g_file_test(path, G_FILE_TEST_IS_REGULAR);
|
||||
if (ok) {
|
||||
InitMatchEquity(path);
|
||||
/* En cas d'échec, gnubg se rabat sans erreur sur la table de Zadeh. */
|
||||
ok = miCurrent.szFileName && strcmp(miCurrent.szFileName, path) == 0;
|
||||
}
|
||||
g_free(path);
|
||||
return ok ? ENGINE_OK : ENGINE_ERROR_DATA;
|
||||
}
|
||||
|
||||
static engine_status
|
||||
load_neural_nets_and_bearoff(const char *data_dir)
|
||||
{
|
||||
char *weights = g_build_filename(data_dir, "gnubg.wd", NULL);
|
||||
int ok = binary_weights_ok(weights);
|
||||
|
||||
if (ok) {
|
||||
EvalInitialise(NULL, weights, FALSE, NULL);
|
||||
/* Bases de fin de partie : gnubg continue sans elles, pas nous. */
|
||||
ok = pbc1 && !pbc1->fHeuristic && pbc2;
|
||||
}
|
||||
g_free(weights);
|
||||
return ok ? ENGINE_OK : ENGINE_ERROR_DATA;
|
||||
}
|
||||
|
||||
engine_status
|
||||
engine_init(const char *data_dir)
|
||||
{
|
||||
engine_status status;
|
||||
|
||||
if (engine_state == READY)
|
||||
return ENGINE_OK;
|
||||
if (engine_state == STOPPED || !data_dir)
|
||||
return ENGINE_ERROR_NOT_INITIALISED;
|
||||
|
||||
gnubg_support_set_data_dir(data_dir);
|
||||
status = load_match_equity_table(data_dir);
|
||||
if (status == ENGINE_OK)
|
||||
status = load_neural_nets_and_bearoff(data_dir);
|
||||
if (status != ENGINE_OK)
|
||||
return status;
|
||||
|
||||
MT_InitThreads();
|
||||
engine_state = READY;
|
||||
return ENGINE_OK;
|
||||
}
|
||||
|
||||
void
|
||||
engine_shutdown(void)
|
||||
{
|
||||
if (engine_state != READY)
|
||||
return;
|
||||
MT_Close();
|
||||
td.tld = NULL;
|
||||
EvalShutdown();
|
||||
engine_state = STOPPED;
|
||||
}
|
||||
|
||||
const char *
|
||||
engine_status_message(engine_status status)
|
||||
{
|
||||
switch (status) {
|
||||
case ENGINE_OK:
|
||||
return "succès";
|
||||
case ENGINE_ERROR_NOT_INITIALISED:
|
||||
return "moteur non initialisé";
|
||||
case ENGINE_ERROR_DATA:
|
||||
return "données du moteur absentes ou invalides";
|
||||
case ENGINE_ERROR_POSITION_ID:
|
||||
return "Position ID invalide";
|
||||
case ENGINE_ERROR_MATCH_ID:
|
||||
return "Match ID invalide";
|
||||
case ENGINE_ERROR_DICE:
|
||||
return "dés invalides (chacun entre 1 et 6)";
|
||||
case ENGINE_ERROR_PLY:
|
||||
return "niveau invalide";
|
||||
case ENGINE_ERROR_TOO_MANY_MOVES:
|
||||
return "tableau de coups trop petit";
|
||||
case ENGINE_ERROR_INTERNAL:
|
||||
return "erreur interne de gnubg";
|
||||
}
|
||||
return "erreur inconnue";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- Décodage */
|
||||
|
||||
/* Vrai si id a exactement length caractères de l'alphabet base64 de gnubg. */
|
||||
static int
|
||||
is_base64_id(const char *id, size_t length)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!id || strlen(id) != length)
|
||||
return 0;
|
||||
for (i = 0; i < length; i++)
|
||||
if (Base64((unsigned char) id[i]) == 255)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
engine_status
|
||||
engine_decode_match(const char *match_id, engine_match *match)
|
||||
{
|
||||
unsigned int dice[2];
|
||||
int turn, resigned, doubled;
|
||||
gamestate state;
|
||||
|
||||
if (!is_base64_id(match_id, L_MATCHID))
|
||||
return ENGINE_ERROR_MATCH_ID;
|
||||
if (MatchFromID(dice, &turn, &resigned, &doubled, &match->player_on_roll,
|
||||
&match->cube_owner, &match->crawford, &match->match_length,
|
||||
match->score, &match->cube_value, &match->jacoby, &state, match_id) != 0)
|
||||
return ENGINE_ERROR_MATCH_ID;
|
||||
return ENGINE_OK;
|
||||
}
|
||||
|
||||
/* Décode Position ID et Match ID, et prépare le cubeinfo de gnubg. */
|
||||
static engine_status
|
||||
decode_position(const char *position_id, const char *match_id, position *pos)
|
||||
{
|
||||
engine_match *m = &pos->match;
|
||||
engine_status status;
|
||||
|
||||
if (engine_state != READY)
|
||||
return ENGINE_ERROR_NOT_INITIALISED;
|
||||
if (!is_base64_id(position_id, L_POSITIONID) || !PositionFromID(pos->board, position_id))
|
||||
return ENGINE_ERROR_POSITION_ID;
|
||||
status = engine_decode_match(match_id, m);
|
||||
if (status != ENGINE_OK)
|
||||
return status;
|
||||
if (SetCubeInfo(&pos->cube, m->cube_value, m->cube_owner, m->player_on_roll,
|
||||
m->match_length, m->score, m->crawford, m->jacoby,
|
||||
DEFAULT_BEAVERS, VARIATION_STANDARD) != 0)
|
||||
return ENGINE_ERROR_MATCH_ID;
|
||||
return ENGINE_OK;
|
||||
}
|
||||
|
||||
static engine_status
|
||||
check_dice(int die1, int die2)
|
||||
{
|
||||
if (die1 < 1 || die1 > 6 || die2 < 1 || die2 > 6)
|
||||
return ENGINE_ERROR_DICE;
|
||||
return ENGINE_OK;
|
||||
}
|
||||
|
||||
/* Réglages prédéfinis de gnubg pour un niveau, sans bruit. */
|
||||
static engine_status
|
||||
eval_context_for_ply(int ply, evalcontext *context)
|
||||
{
|
||||
if (ply < 0 || ply > ENGINE_MAX_PLY)
|
||||
return ENGINE_ERROR_PLY;
|
||||
*context = aecSettings[SETTINGS_0PLY + ply];
|
||||
return ENGINE_OK;
|
||||
}
|
||||
|
||||
/* En match, gnubg calcule en chances de gain du match : on convertit. */
|
||||
static float
|
||||
normalized_equity(float score, const cubeinfo *cube)
|
||||
{
|
||||
return cube->nMatchTo ? mwc2eq(score, cube) : score;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ Coups */
|
||||
|
||||
static void
|
||||
fill_move(engine_move *out, const move *m, const position *pos, int evaluated)
|
||||
{
|
||||
int i;
|
||||
|
||||
FormatMove(out->notation, (ConstTanBoard) pos->board, m->anMove);
|
||||
snprintf(out->position_id, sizeof out->position_id, "%s", PositionIDFromKey(&m->key));
|
||||
out->ply = evaluated ? (int) m->esMove.ec.nPlies : -1;
|
||||
for (i = 0; i < ENGINE_NUM_PROBABILITIES; i++)
|
||||
out->probabilities[i] = evaluated ? m->arEvalMove[i] : 0.0f;
|
||||
out->equity = evaluated ? normalized_equity(m->rScore, &pos->cube) : 0.0f;
|
||||
}
|
||||
|
||||
engine_status
|
||||
engine_legal_moves(const char *position_id, const char *match_id, int die1, int die2,
|
||||
engine_move *moves, int max_moves, int *count)
|
||||
{
|
||||
position pos;
|
||||
movelist list;
|
||||
engine_status status;
|
||||
unsigned int i;
|
||||
|
||||
status = decode_position(position_id, match_id, &pos);
|
||||
if (status == ENGINE_OK)
|
||||
status = check_dice(die1, die2);
|
||||
if (status != ENGINE_OK)
|
||||
return status;
|
||||
|
||||
/* La liste pointe vers un tableau interne de gnubg : rien à libérer. */
|
||||
GenerateMoves(&list, (ConstTanBoard) pos.board, die1, die2, FALSE);
|
||||
if (list.cMoves > (unsigned int) max_moves)
|
||||
return ENGINE_ERROR_TOO_MANY_MOVES;
|
||||
for (i = 0; i < list.cMoves; i++)
|
||||
fill_move(&moves[i], &list.amMoves[i], &pos, 0);
|
||||
*count = (int) list.cMoves;
|
||||
return ENGINE_OK;
|
||||
}
|
||||
|
||||
engine_status
|
||||
engine_best_moves(const char *position_id, const char *match_id, int die1, int die2, int ply,
|
||||
engine_move *moves, int max_moves, int *count)
|
||||
{
|
||||
position pos;
|
||||
movelist list;
|
||||
evalcontext context;
|
||||
engine_status status;
|
||||
unsigned int i;
|
||||
|
||||
status = decode_position(position_id, match_id, &pos);
|
||||
if (status == ENGINE_OK)
|
||||
status = check_dice(die1, die2);
|
||||
if (status == ENGINE_OK)
|
||||
status = eval_context_for_ply(ply, &context);
|
||||
if (status != ENGINE_OK)
|
||||
return status;
|
||||
|
||||
/* Comme la commande « hint » de gnubg, avec les filtres « normaux ». */
|
||||
if (FindnSaveBestMoves(&list, die1, die2, (ConstTanBoard) pos.board, NULL, FALSE, 0.0f,
|
||||
&pos.cube, &context, aaamfMoveFilterSettings[0]) < 0)
|
||||
return ENGINE_ERROR_INTERNAL;
|
||||
|
||||
status = ENGINE_OK;
|
||||
if (list.cMoves > (unsigned int) max_moves)
|
||||
status = ENGINE_ERROR_TOO_MANY_MOVES;
|
||||
else {
|
||||
for (i = 0; i < list.cMoves; i++)
|
||||
fill_move(&moves[i], &list.amMoves[i], &pos, 1);
|
||||
*count = (int) list.cMoves;
|
||||
}
|
||||
g_free(list.amMoves);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- Évaluation et videau */
|
||||
|
||||
engine_status
|
||||
engine_evaluate(const char *position_id, const char *match_id, int ply,
|
||||
engine_evaluation *evaluation)
|
||||
{
|
||||
position pos;
|
||||
evalcontext context;
|
||||
float output[NUM_ROLLOUT_OUTPUTS];
|
||||
engine_status status;
|
||||
int i;
|
||||
|
||||
status = decode_position(position_id, match_id, &pos);
|
||||
if (status == ENGINE_OK)
|
||||
status = eval_context_for_ply(ply, &context);
|
||||
if (status != ENGINE_OK)
|
||||
return status;
|
||||
|
||||
if (GeneralEvaluationE(output, (ConstTanBoard) pos.board, &pos.cube, &context) < 0)
|
||||
return ENGINE_ERROR_INTERNAL;
|
||||
|
||||
for (i = 0; i < ENGINE_NUM_PROBABILITIES; i++)
|
||||
evaluation->probabilities[i] = output[i];
|
||||
evaluation->cubeless_equity = output[OUTPUT_EQUITY];
|
||||
evaluation->cubeful_equity = normalized_equity(output[OUTPUT_CUBEFUL_EQUITY], &pos.cube);
|
||||
return ENGINE_OK;
|
||||
}
|
||||
|
||||
/* Noms anglais des décisions, dans l'ordre de l'énumération cubedecision. */
|
||||
static const char *const cube_decision_names[] = {
|
||||
"double_take", "double_pass", "no_double_take", "too_good_take", "too_good_pass",
|
||||
"double_beaver", "no_double_beaver", "redouble_take", "redouble_pass",
|
||||
"no_redouble_take", "too_good_redouble_take", "too_good_redouble_pass",
|
||||
"no_redouble_beaver", "no_double_dead_cube", "no_redouble_dead_cube",
|
||||
"not_available", "optional_double_take", "optional_redouble_take",
|
||||
"optional_double_beaver", "optional_double_pass", "optional_redouble_pass"
|
||||
};
|
||||
|
||||
engine_status
|
||||
engine_cube_decision(const char *position_id, const char *match_id, int ply, engine_cube *cube)
|
||||
{
|
||||
position pos;
|
||||
evalcontext context;
|
||||
float output[2][NUM_ROLLOUT_OUTPUTS];
|
||||
float equities[4];
|
||||
cubedecision decision;
|
||||
engine_status status;
|
||||
int i;
|
||||
|
||||
status = decode_position(position_id, match_id, &pos);
|
||||
if (status == ENGINE_OK)
|
||||
status = eval_context_for_ply(ply, &context);
|
||||
if (status != ENGINE_OK)
|
||||
return status;
|
||||
|
||||
if (GeneralCubeDecisionE(output, (ConstTanBoard) pos.board, &pos.cube, &context, NULL) < 0)
|
||||
return ENGINE_ERROR_INTERNAL;
|
||||
/* FindCubeDecision renvoie des équités déjà normalisées. */
|
||||
decision = FindCubeDecision(equities, output, &pos.cube);
|
||||
if ((size_t) decision >= sizeof cube_decision_names / sizeof cube_decision_names[0])
|
||||
return ENGINE_ERROR_INTERNAL;
|
||||
|
||||
for (i = 0; i < ENGINE_NUM_PROBABILITIES; i++)
|
||||
cube->probabilities[i] = output[0][i];
|
||||
cube->no_double = equities[OUTPUT_NODOUBLE];
|
||||
cube->double_take = equities[OUTPUT_TAKE];
|
||||
cube->double_pass = equities[OUTPUT_DROP];
|
||||
cube->decision = cube_decision_names[decision];
|
||||
return ENGINE_OK;
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* engine.h -- interface C du moteur de backgammon d'Ustagammon.
|
||||
*
|
||||
* Copyright (C) 2026 les auteurs d'Ustagammon.
|
||||
* Licence : GPLv3 ou ultérieure (voir LICENSE).
|
||||
*
|
||||
* Le moteur est le cœur de GNU Backgammon (engine/gnubg/), seule autorité
|
||||
* pour les règles, les coups, le videau et les évaluations. Cette interface
|
||||
* n'expose aucun type de gnubg.
|
||||
*
|
||||
* Positions : une position est décrite par deux identifiants de gnubg,
|
||||
* - le Position ID (14 caractères), qui code le plateau du point de vue du
|
||||
* joueur au trait ;
|
||||
* - le Match ID (12 caractères), qui code le reste : longueur du match (0 en
|
||||
* partie libre), score, videau et son propriétaire, joueur au trait,
|
||||
* Crawford, Jacoby. Les dés éventuellement codés dans le Match ID sont
|
||||
* ignorés : les dés sont passés à part.
|
||||
*
|
||||
* Niveaux (« ply ») : réglages prédéfinis de gnubg, sans bruit, de 0
|
||||
* (évaluation statique du réseau) à 4. gnubg compte les plis à partir de 0.
|
||||
*
|
||||
* Équités : toujours du point de vue du joueur au trait, normalisées pour
|
||||
* un videau de 1. En match, gnubg convertit les chances de gain du match en
|
||||
* équité normalisée, comme il l'affiche par défaut.
|
||||
*
|
||||
* Probabilités, dans l'ordre de gnubg : gain, gain gammon, gain backgammon,
|
||||
* perte gammon, perte backgammon (les gammons incluent les backgammons).
|
||||
*
|
||||
* Contraintes : une seule instance du moteur (état global de gnubg) et des
|
||||
* appels sérialisés, jamais concurrents. Toutes les fonctions renvoient un
|
||||
* code engine_status ; aucune ne termine le programme pour une erreur
|
||||
* d'utilisation.
|
||||
*/
|
||||
|
||||
#ifndef USTAGAMMON_ENGINE_H
|
||||
#define USTAGAMMON_ENGINE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ENGINE_OK = 0,
|
||||
ENGINE_ERROR_NOT_INITIALISED, /* engine_init n'a pas réussi */
|
||||
ENGINE_ERROR_DATA, /* données absentes ou invalides */
|
||||
ENGINE_ERROR_POSITION_ID, /* Position ID invalide */
|
||||
ENGINE_ERROR_MATCH_ID, /* Match ID invalide */
|
||||
ENGINE_ERROR_DICE, /* dés hors de 1..6 */
|
||||
ENGINE_ERROR_PLY, /* niveau hors de 0..ENGINE_MAX_PLY */
|
||||
ENGINE_ERROR_TOO_MANY_MOVES, /* tableau de coups trop petit */
|
||||
ENGINE_ERROR_INTERNAL /* échec signalé par gnubg */
|
||||
} engine_status;
|
||||
|
||||
#define ENGINE_MAX_PLY 4
|
||||
|
||||
/* Nombre maximal de coups légaux pour un jet (MAX_MOVES de gnubg). */
|
||||
#define ENGINE_MAX_MOVES 3060
|
||||
|
||||
/* Indices du tableau probabilities. */
|
||||
enum {
|
||||
ENGINE_WIN = 0,
|
||||
ENGINE_WIN_GAMMON,
|
||||
ENGINE_WIN_BACKGAMMON,
|
||||
ENGINE_LOSE_GAMMON,
|
||||
ENGINE_LOSE_BACKGAMMON,
|
||||
ENGINE_NUM_PROBABILITIES
|
||||
};
|
||||
|
||||
/* Un coup, avec son évaluation quand il a été classé. */
|
||||
typedef struct {
|
||||
char notation[32]; /* notation de gnubg, ex. « 8/5 6/5 » */
|
||||
char position_id[16]; /* Position ID après le coup, plateau vu du
|
||||
* joueur qui vient de jouer */
|
||||
int ply; /* niveau de l'évaluation (-1 : non évalué) */
|
||||
float probabilities[ENGINE_NUM_PROBABILITIES];
|
||||
float equity; /* équité de classement (avec videau) */
|
||||
} engine_move;
|
||||
|
||||
/* Évaluation d'une position, joueur au trait avant de lancer les dés. */
|
||||
typedef struct {
|
||||
float probabilities[ENGINE_NUM_PROBABILITIES];
|
||||
float cubeless_equity; /* équité sans videau */
|
||||
float cubeful_equity; /* équité avec videau */
|
||||
} engine_evaluation;
|
||||
|
||||
/* Décision de videau du joueur au trait, avant de lancer les dés. */
|
||||
typedef struct {
|
||||
float probabilities[ENGINE_NUM_PROBABILITIES];
|
||||
float no_double; /* équité si pas de double */
|
||||
float double_take; /* équité si double et prend */
|
||||
float double_pass; /* équité si double et passe */
|
||||
const char *decision; /* décision de gnubg, en anglais : « no_double_take »,
|
||||
* « double_take », « double_pass »,
|
||||
* « too_good_pass », « not_available »… */
|
||||
} engine_cube;
|
||||
|
||||
/* Description lisible d'un Match ID décodé. */
|
||||
typedef struct {
|
||||
int match_length; /* 0 : partie libre (money game) */
|
||||
int score[2];
|
||||
int cube_value;
|
||||
int cube_owner; /* -1 : videau au centre ; sinon 0 ou 1 */
|
||||
int player_on_roll; /* 0 ou 1 */
|
||||
int crawford; /* partie Crawford en cours */
|
||||
int jacoby; /* règle Jacoby (partie libre) */
|
||||
} engine_match;
|
||||
|
||||
/*
|
||||
* Charge les données du moteur depuis data_dir : gnubg.wd (réseaux),
|
||||
* gnubg_os0.bd et gnubg_ts0.bd (fins de partie), Kazaross-XG2.xml (table
|
||||
* d'équité de match). À appeler une fois avant toute autre fonction.
|
||||
*/
|
||||
engine_status engine_init(const char *data_dir);
|
||||
|
||||
/* Libère les ressources. Le moteur ne peut pas être réinitialisé ensuite. */
|
||||
void engine_shutdown(void);
|
||||
|
||||
/* Message d'erreur en français pour un code de retour. */
|
||||
const char *engine_status_message(engine_status status);
|
||||
|
||||
/* Décode un Match ID. */
|
||||
engine_status engine_decode_match(const char *match_id, engine_match *match);
|
||||
|
||||
/*
|
||||
* Coups légaux pour une position et un jet (die1, die2 dans 1..6), sans
|
||||
* évaluation (ply vaut -1). moves doit pouvoir contenir max_moves coups ;
|
||||
* ENGINE_MAX_MOVES suffit toujours. *count reçoit le nombre de coups (0 si
|
||||
* le joueur ne peut pas jouer).
|
||||
*/
|
||||
engine_status engine_legal_moves(const char *position_id, const char *match_id,
|
||||
int die1, int die2,
|
||||
engine_move *moves, int max_moves, int *count);
|
||||
|
||||
/*
|
||||
* Coups légaux classés du meilleur au moins bon, au niveau ply. Comme dans
|
||||
* gnubg, les coups écartés par les filtres gardent l'évaluation du niveau
|
||||
* inférieur (voir leur champ ply).
|
||||
*/
|
||||
engine_status engine_best_moves(const char *position_id, const char *match_id,
|
||||
int die1, int die2, int ply,
|
||||
engine_move *moves, int max_moves, int *count);
|
||||
|
||||
/* Évaluation d'une position au niveau ply. */
|
||||
engine_status engine_evaluate(const char *position_id, const char *match_id,
|
||||
int ply, engine_evaluation *evaluation);
|
||||
|
||||
/* Décision de videau au niveau ply. */
|
||||
engine_status engine_cube_decision(const char *position_id, const char *match_id,
|
||||
int ply, engine_cube *cube);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USTAGAMMON_ENGINE_H */
|
||||
Reference in New Issue
Block a user