-
Notifications
You must be signed in to change notification settings - Fork 0
/
engine.cpp
98 lines (87 loc) · 3.66 KB
/
engine.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Connect4 computer player
// providing different agents for selecting a move (random, request server)
//
// Written by Stefan Abendroth <sab@ab-solut.com>
// Last updated: 2022-02-11
#include "engine.hpp"
using namespace std;
size_t curl_callback(void *ptr, size_t size, size_t nmemb, string* data)
// write callback function for POST request
{
data->append((char*)ptr, size * nmemb);
return size * nmemb;
}
Engine::Engine()
{
srand(time(NULL));
}
uint8_t Engine::random_agent()
// Generate random move without looking at the board
// move may be invalid (full column)
{
return rand()%7;
}
uint8_t Engine::server_agent(uint8_t tiles[ROWS][COLUMNS], uint8_t player)
// Get move from api.codebox.net/connect4
// Only works with standard board size (6 rows, 7 columns)
// Command line example: curl -X POST api.codebox.net/connect4 -H 'Content-Type: application/json' -d '{"board":["...0...","...1...","...01..","...10..","...01..","...110."]}'
// Server expects board state in JSON format like {["...0...","...1...","...01..","...10..","...01..","...110."]},
// where "." is empty, "0" is server and "1" is human player, from top to bottom
// If no error, server responds with JSON format, e.g. {"move": 1, "winner": null}.
// "move" data is extracted and returned. "winner" data is ignored (winner is determined by local function). In case of error, random_agent is called.
{
uint8_t result;
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL; // linked-list string structure
string response_string; // will contain server response
string tile_char;
string move_char;
// create server input string
string post_string = "{\"board\":[\".......\",\".......\",\".......\",\".......\",\".......\",\".......\"]}"; // empty board
for (uint8_t row=0; row<ROWS; row++)
for (uint8_t col=0; col<COLUMNS; col++)
if (tiles[row][col])
{
if (tiles[row][col]==player) // server expects "0" for own tiles and "1" for opponent
tile_char="0";
else
tile_char="1";
post_string.replace (11+10*row+col,1,tile_char); // replace single character at right string position
}
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "api.codebox.net/connect4");
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_string.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);
// Perform the request, res will get the return code
res = curl_easy_perform(curl);
if(res == CURLE_OK)
{
// extract server response
move_char=response_string.substr(9,1); // 9th character contains selected column
result=stoi(move_char);
}
else
result=random_agent();
curl_easy_cleanup(curl);
}
else
result=random_agent();
return result;
}
uint8_t Engine::propose_move(uint8_t tiles[ROWS][COLUMNS], uint8_t player, uint8_t level)
// Deliver move of player (1 or 2), according to current board state defined by array tiles.
// level 0 will use random moves only, while level 9 uses server moves only.
// Any number inbetween mixes random and server moves with increasing probability for server moves.
{
uint8_t result;
if (rand()%9 < level)
result=server_agent(tiles, player);
else
result=random_agent();
return result;
}