Skip to content

Commit d9e7a9c

Browse files
committed
ajout d'une api pour les bots et du protocole de communication
1 parent e5f85dd commit d9e7a9c

11 files changed

Lines changed: 378 additions & 59 deletions

File tree

Makefile

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# === VARIABLES ===
22
CC := gcc
3-
CFLAGS := -Wall -Wextra -std=c11
3+
CFLAGS := -Wall -Wextra -std=c11 -D_POSIX_C_SOURCE=200809L
44

55
SRC_DIR := src
66
INCLUDE_DIR := lib
@@ -14,7 +14,7 @@ LDLIBS := `sdl2-config --libs` -lSDL2_image
1414

1515
# === SOURCES ===
1616
SRC_FILES := $(shell find $(SRC_DIR) -name "*.c")
17-
SRC_FILES := $(filter-out $(SRC_DIR)/main_ai.c, $(SRC_FILES))
17+
SRC_FILES := $(filter-out $(SRC_DIR)/api_bot.c, $(SRC_FILES))
1818
OBJ_FILES := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRC_FILES))
1919

2020
BOT_SRC_FILES := $(shell find $(SRC_DIR) -name "*.c")
@@ -38,10 +38,13 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
3838
@echo "🛠️ Compiling $<"
3939
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
4040

41+
BOT_EXEC := bots/bot_v0
42+
BOT_DIR := bots
43+
4144
$(BOT_EXEC): $(BOT_OBJ_FILES)
42-
@mkdir -p $(BUILD_DIR)
43-
@echo "🔗 Linkage (bot)..."
44-
$(CC) $(BOT_OBJ_FILES) -o $@ $(LDLIBS)
45+
@mkdir -p $(BOT_DIR)
46+
@echo "🔗 Linking bot executable..."
47+
$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LDLIBS)
4548

4649

4750
# === EXÉCUTIONS ===
@@ -68,14 +71,17 @@ re: clean all
6871
TEST_DIR := tests
6972
TEST_SRC := $(shell find $(TEST_DIR) -name "*.c")
7073

71-
# On prend toutes les sources dans src/chessboard (et sous-dossiers) sauf main.c
7274
SRC_CHESSBOARD := $(shell find $(SRC_DIR)/chessboard -name "*.c")
73-
OBJ_CHESSBOARD := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRC_CHESSBOARD))
75+
SRC_API := $(shell find $(SRC_DIR)/api -name "*.c")
7476

75-
test: $(OBJ_CHESSBOARD) $(TEST_SRC)
77+
TEST_SRC_FILES := $(SRC_CHESSBOARD) $(SRC_API)
78+
TEST_OBJ_FILES := $(TEST_SRC_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
79+
80+
test: $(TEST_OBJ_FILES)
7681
@mkdir -p $(BUILD_DIR)
7782
@echo "🧪 Compilation des tests..."
78-
$(CC) $(CFLAGS) $(INCLUDES) $^ -o $(TEST_EXEC) -lcriterion
83+
$(CC) $(CFLAGS) $(INCLUDES) $(TEST_OBJ_FILES) $(TEST_SRC) -o $(TEST_EXEC) -lcriterion
7984
@echo "🚀 Lancement des tests..."
8085
ulimit -s unlimited && ./$(TEST_EXEC) --jobs 1
8186

87+

bots/bot_v0

74.4 KB
Binary file not shown.

documentations/bot_api.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Bot Chess API — Documentation minimale
2+
3+
## Description
4+
Cette API permet la communication entre le moteur principal du jeu d’échecs et un bot IA exécuté dans un processus séparé.
5+
La communication se fait par **pipes** (entrée/sortie standard).
6+
7+
## Structure
8+
### BotConnector
9+
Contient les informations nécessaires pour interagir avec le processus du bot :
10+
- `FILE *bot_in` : flux d’écriture vers le bot (stdin du bot)
11+
- `FILE *bot_out` : flux de lecture depuis le bot (stdout du bot)
12+
- `pid_t pid` : identifiant du processus du bot
13+
14+
## Fonctions principales
15+
16+
### bot_connect
17+
Lance le processus du bot et initialise la communication via pipes.
18+
19+
### is_bot_connected
20+
Vérifie que la connexion au bot est toujours active.
21+
22+
### bot_set_fen
23+
Envoie une position FEN au bot pour mettre à jour son état interne.
24+
25+
### bot_get_best_move
26+
Demande au bot de calculer et renvoyer son meilleur coup.
27+
28+
### bot_play_move
29+
Envoie un coup joué pour que le bot mette à jour sa position interne.
30+
31+
### bot_disconnect
32+
Ferme proprement la communication et termine le processus du bot.
33+
34+
## Protocole de communication
35+
36+
| Commande envoyée | Réponse attendue | Description |
37+
|------------------|------------------|--------------|
38+
| `fen <FEN>` | *(aucune)* | Met à jour la position interne. |
39+
| `get move` | `<MOVE>` | Retourne le meilleur coup. |
40+
| `move <MOVE>` | *(aucune)* | Joue le coup donné. |
41+
| `quit` | *(aucune)* | Termine le bot proprement. |
42+
43+
## Notes
44+
- Le bot doit désactiver le buffering (`setvbuf(stdout, NULL, _IONBF, 0)`).
45+
- Chaque réponse doit se terminer par un saut de ligne (`\n`) et être flushée (`fflush(stdout)`).

lib/api/api_connector.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef API_CONNECTOR_H
2+
#define API_CONNECTOR_H
3+
4+
#include <fcntl.h>
5+
#include <sys/types.h>
6+
#include <sys/stat.h>
7+
#include <unistd.h>
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
#include <string.h>
11+
#include <sys/select.h>
12+
#include <errno.h>
13+
#include <sys/wait.h>
14+
15+
#define MOVE_SIZE 10
16+
#define FEN_SIZE 256
17+
18+
typedef struct
19+
{
20+
FILE *bot_in;
21+
FILE *bot_out;
22+
pid_t pid;
23+
} BotConnector;
24+
25+
// Initialise la connexion avec le bot exécutable
26+
int bot_connect(BotConnector *bot, const char *bot_path);
27+
28+
int is_bot_connected(BotConnector *bot);
29+
30+
int bot_set_fen(BotConnector *bot, const char *fen);
31+
32+
// Demande au bot le meilleur coup pour un FEN et une couleur
33+
int bot_get_best_move(BotConnector *bot, char *move_str);
34+
35+
// Envoie un coup au bot pour mise à jour de son état interne
36+
int bot_play_move(BotConnector *bot, const char *move_str);
37+
38+
// Ferme proprement la connexion avec le bot
39+
void bot_disconnect(BotConnector *bot);
40+
41+
#endif
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "tools/dynamic_list.h"
55
#include "ai/ai.h"
66
#include "ai/evaluation.h"
7+
#include "api_connector.h"
78

89
#include <SDL2/SDL.h>
910
#include <SDL2/SDL_image.h>
File renamed without changes.

src/api/api_connector.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#include "api_connector.h"
2+
3+
static int read_line_timeout(FILE *stream, char *buf, int size, int timeout_sec)
4+
{
5+
int fd = fileno(stream);
6+
fd_set readfds;
7+
struct timeval tv;
8+
9+
FD_ZERO(&readfds);
10+
FD_SET(fd, &readfds);
11+
12+
tv.tv_sec = timeout_sec;
13+
tv.tv_usec = 0;
14+
15+
int ret = select(fd + 1, &readfds, NULL, NULL, &tv);
16+
if (ret == -1)
17+
return -1; // erreur
18+
if (ret == 0)
19+
return -2; // timeout
20+
21+
if (fgets(buf, size, stream) == NULL)
22+
return -3; // EOF ou erreur
23+
24+
buf[strcspn(buf, "\r\n")] = '\0';
25+
return 0;
26+
}
27+
28+
// --- API ---
29+
30+
int bot_connect(BotConnector *bot, const char *bot_path)
31+
{
32+
int to_bot[2]; // pipe père -> bot
33+
int from_bot[2]; // pipe bot -> père
34+
35+
if (pipe(to_bot) == -1 || pipe(from_bot) == -1)
36+
return -1;
37+
38+
pid_t pid = fork();
39+
if (pid == -1)
40+
return -1;
41+
42+
if (pid == 0) // enfant
43+
{
44+
// redirection stdin/out
45+
dup2(to_bot[0], STDIN_FILENO);
46+
dup2(from_bot[1], STDOUT_FILENO);
47+
48+
close(to_bot[1]);
49+
close(from_bot[0]);
50+
51+
execl(bot_path, bot_path, NULL);
52+
perror("execl");
53+
exit(1);
54+
}
55+
56+
// père
57+
close(to_bot[0]);
58+
close(from_bot[1]);
59+
60+
bot->bot_in = fdopen(to_bot[1], "w");
61+
bot->bot_out = fdopen(from_bot[0], "r");
62+
bot->pid = pid;
63+
64+
if (!bot->bot_in || !bot->bot_out)
65+
return -1;
66+
67+
// Pas de buffering pour éviter les blocages
68+
setvbuf(bot->bot_in, NULL, _IONBF, 0);
69+
setvbuf(bot->bot_out, NULL, _IONBF, 0);
70+
71+
return 0;
72+
}
73+
74+
int is_bot_connected(BotConnector *bot)
75+
{
76+
return bot && bot->bot_in && bot->bot_out;
77+
}
78+
79+
int bot_set_fen(BotConnector *bot, const char *fen)
80+
{
81+
if (!is_bot_connected(bot))
82+
return -1;
83+
84+
fprintf(bot->bot_in, "fen %s\n", fen);
85+
fflush(bot->bot_in);
86+
return 0;
87+
}
88+
89+
int bot_get_best_move(BotConnector *bot, char *move_str)
90+
{
91+
if (!is_bot_connected(bot))
92+
return -1;
93+
94+
fprintf(bot->bot_in, "get move\n");
95+
fflush(bot->bot_in);
96+
97+
int res = read_line_timeout(bot->bot_out, move_str, MOVE_SIZE, 3); // timeout 3s
98+
99+
if (res != 0)
100+
return -1;
101+
102+
return 0;
103+
}
104+
105+
int bot_play_move(BotConnector *bot, const char *move_str)
106+
{
107+
if (!is_bot_connected(bot))
108+
return -1;
109+
110+
fprintf(bot->bot_in, "move %s\n", move_str);
111+
fflush(bot->bot_in);
112+
return 0;
113+
}
114+
115+
void bot_disconnect(BotConnector *bot)
116+
{
117+
if (!bot)
118+
return;
119+
120+
if (bot->bot_in)
121+
fclose(bot->bot_in);
122+
if (bot->bot_out)
123+
fclose(bot->bot_out);
124+
125+
if (bot->pid > 0)
126+
waitpid(bot->pid, NULL, 0);
127+
128+
bot->bot_in = NULL;
129+
bot->bot_out = NULL;
130+
bot->pid = 0;
131+
}

src/api_bot.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include <stdio.h>
2+
#include <string.h>
3+
#include "chessboard/chessboardcontroller.h"
4+
#include "chessboard/chessboard.h"
5+
#include "ai/ai.h"
6+
7+
#define STARTPOS "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
8+
9+
#define CMD_SIZE 256
10+
#define FEN_SIZE 256
11+
12+
int is_bot_killed(char *command, size_t size)
13+
{
14+
if (fgets(command, size, stdin) == NULL)
15+
return 1;
16+
17+
command[strcspn(command, "\r\n")] = '\0';
18+
19+
if (strncmp(command, "quit", 4) == 0)
20+
return 1;
21+
22+
return 0;
23+
}
24+
25+
void handle_commands(const char *command, Chessboard *board, char *fen)
26+
{
27+
if (strncmp(command, "get move", 8) == 0)
28+
{
29+
Move best_move = get_best_move(*board);
30+
print_move(&best_move);
31+
printf("\n");
32+
fflush(stdout);
33+
}
34+
else if (strncmp(command, "fen ", 4) == 0)
35+
{
36+
strncpy(fen, command + 4, FEN_SIZE - 1);
37+
fen[FEN_SIZE - 1] = '\0';
38+
init_chessboard_from_fen(board, fen);
39+
}
40+
else if (strncmp(command, "move ", 5) == 0)
41+
{
42+
char move[10] = {0};
43+
strncpy(move, command + 5, 4);
44+
Move m = get_move(move);
45+
try_play_move(board, &m);
46+
}
47+
}
48+
49+
int main(void)
50+
{
51+
setvbuf(stdout, NULL, _IONBF, 0);
52+
53+
char fen[FEN_SIZE] = STARTPOS;
54+
Chessboard board;
55+
init_chessboard_from_fen(&board, fen);
56+
57+
char command[CMD_SIZE];
58+
59+
while (1)
60+
{
61+
if (is_bot_killed(command, sizeof(command)))
62+
break;
63+
64+
handle_commands(command, &board, fen);
65+
}
66+
67+
return 0;
68+
}

0 commit comments

Comments
 (0)