#define _CRT_SECURE_NO_WARNINGS
#ifdef UNICODE
#undef UNICODE
#endif
#include<iostream>
#include<string>
#include<memory.h>
#include<set>
#include<deque>
#include<vector>
#include<easyx.h>
#include<graphics.h>
#include<conio.h>
#define WIDTH 450
#define HEIGHT 450
using namespace std;
struct mm
{
int x;
int y;
};
mm my = { 0,0 };
//全局声明
// 结果枚举
enum GameResult { CONTINUE, BLACK_WIN, WHITE_WIN, DRAW };
// 全局变量,用于记录胜负结果
int blackWins = 0;//AI胜利
int whiteWins = 0;//玩家胜利
// 函数声明
GameResult checkGameResult(uint8_t board[15][15]);
void showResultDialog(GameResult result);
void drawWinRate();
void machine_human_play();
// 在游戏结束后显示胜负结果对话框,并根据用户选择决定下一步操作
void showResultDialog(GameResult result) {
string message;
if (result == BLACK_WIN) {
message = "黑棋获胜!是否开始下一局?";
blackWins++;
}
else if (result == WHITE_WIN) {
message = "白棋获胜!是否开始下一局?";
whiteWins++;
}
else {
message = "平局!是否开始下一局?";
}
int choice = MessageBox(GetHWnd(), message.c_str(), "游戏结束", MB_YESNO);
if (choice == IDYES) {
// 清空棋盘并重新开始游戏
cleardevice();
machine_human_play();
}
else {
// 退出游戏
closegraph();
exit(0);
}
}
// 在左上角显示胜负比例
void drawWinRate() {
char rateStr[256] = "";
double totalGames = blackWins + whiteWins;
// double blackWinRate = (blackWins / totalGames) * 100.0;
// double whiteWinRate = (whiteWins / totalGames) * 100.0;
double AIUSER = (whiteWins / totalGames) * 100;
sprintf(rateStr, "<第%.0f场>_[AI黑 VS 玩家白]_<%d:%d>_玩家胜率<%0.2lf ﹪>",
totalGames + 1, (int)blackWins, (int)whiteWins, AIUSER);
settextstyle(15, 0, "宋体");
settextcolor(YELLOW);
outtextxy(25, 5, rateStr);
}
// 在游戏结束后检查胜负结果
GameResult checkGameResult(uint8_t board[15][15]) {
// 这里添加你检查胜负结果的代码
return CONTINUE;
}
//
class GameTree {
private:
class Node {
public:
int32_t value;
uint32_t depth;
Node* father;
set<Node*> children;
uint8_t cntX, cntY;
uint8_t board[15][15]{};
Node() {
father = nullptr;
children.clear();
value = INT32_MIN;
depth = cntX = cntY = 0;
memset(board, 0, sizeof(board));
}
Node(Node* node, uint8_t opeX, uint8_t opeY) {
depth = node->depth + 1;
value = is_max_node() ? INT32_MIN : INT32_MAX;
father = node;
children.clear();
cntX = opeX;
cntY = opeY;
memcpy(board, node->board, sizeof(board));
board[cntX][cntY] = (depth & 1u) ? 'B' : 'W';
}
bool is_max_node() {
return (depth & 1u) ^ 1u;
}
static int32_t evaluate_black(string& s) {
string patterns[31] = {
"B0000", "0B000", "00B00", "000B0", "0000B",
"BB000", "0BB00", "00BB0", "000BB", "B0B00", "0B0B0", "00B0B", "B00B0", "0B00B", "B000B",
"BBB00", "0BBB0", "00BBB", "BB0B0", "0BB0B", "B0BB0", "0B0BB", "BB00B", "B00BB", "B0B0B",
"BBBB0", "BBB0B", "BB0BB", "B0BBB", "0BBBB", "BBBBB",
};
int32_t scores[31] = {
1, 1, 1, 1, 1,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
10000, 10000, 10000, 10000, 10000, 1000000,
};
for (uint8_t i = 0; i < 31; i++)
if (s == patterns[i]) return scores[i];
return 0;
}
static int32_t evaluate_white(string& s) {
string patterns[31] = {
"W0000", "0W000", "00W00", "000W0", "0000W",
"WW000", "0WW00", "00WW0", "000WW", "W0W00", "0W0W0", "00W0W", "W00W0", "0W00W", "W000W",
"WWW00", "0WWW0", "00WWW", "WW0W0", "0WW0W", "W0WW0", "0W0WW", "WW00W", "W00WW", "W0W0W",
"WWWW0", "WWW0W", "WW0WW", "W0WWW", "0WWWW", "WWWWW",
};
int32_t scores[31] = {
1, 1, 1, 1, 1,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
1000, 2000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000,
100000, 100000, 100000, 100000, 100000, 10000000,
};
for (uint8_t i = 0; i < 31; i++)
if (s == patterns[i]) return scores[i];
return 0;
}
static string convert(uint8_t pos) {
if (pos == 0) return "0";
if (pos == 'B') return "B"; else return "W";
}
uint8_t board_identify() {
for (uint8_t i = 0; i < 15; i++)
for (uint8_t j = 0; j < 15; j++) {
if (j + 4 < 15) {
string s;
for (uint8_t k = 0; k < 5; k++) s += convert(board[i][j + k]);
if (s == "BBBBB") return 'B';
if (s == "WWWWW") return 'W';
}
if (i + 4 < 15) {
string s;
for (uint8_t k = 0; k < 5; k++) s += convert(board[i + k][j]);
if (s == "BBBBB") return 'B';
if (s == "WWWWW") return 'W';
}
if (i + 4 < 15 && j + 4 < 15) {
string s;
for (uint8_t k = 0; k < 5; k++) s += convert(board[i + k][j + k]);
if (s == "BBBBB") return 'B';
if (s == "WWWWW") return 'W';
}
if (i + 4 < 15 && j - 4 >= 0) {
string s;
for (uint8_t k = 0; k < 5; k++) s += convert(board[i + k][j - k]);
if (s == "BBBBB") return 'B';
if (s == "WWWWW") return 'W';
}
}
return 0;
}
void evaluate() {
value = 0;
for (uint8_t i = 0; i < 15; i++)
for (uint8_t j = 0; j < 15; j++) {
if (j + 4 < 15) {
string s;
for (uint8_t k = 0; k < 5; k++) s += convert(board[i][j + k]);
value += evaluate_black(s) - evaluate_white(s);
}
if (i + 4 < 15) {
string s;
for (uint8_t k = 0; k < 5; k++) s += convert(board[i + k][j]);
value += evaluate_black(s) - evaluate_white(s);
}
if (i + 4 < 15 && j + 4 < 15) {
string s;
for (uint8_t k = 0; k < 5; k++) s += convert(board[i + k][j + k]);
value += evaluate_black(s) - evaluate_white(s);
}
if (i + 4 < 15 && j - 4 >= 0) {
string s;
for (uint8_t k = 0; k < 5; k++) s += convert(board[i + k][j - k]);
value += evaluate_black(s) - evaluate_white(s);
}
}
}
void print_info() {
cout << this << " depth=" << depth << " value=" << value << " father=" << father << " children=(";
for (auto child : children) cout << child << ",";
cout << ")" << endl;
for (auto& i : board) {
cout << " ";
for (uint8_t j : i) {
if (j == 'B') cout << "○";
if (j == 'W') cout << "●";
if (j == 0) cout << "┼";
}
cout << endl;
}
}
};
uint8_t expandRadius = 2;
uint32_t maxDepth = 5;
Node* nodeRoot = new Node();
Node* nodeNext = nullptr;
deque<Node*> openTable;
deque<Node*> closedTable;
vector<pair<uint8_t, uint8_t>> get_search_nodes(Node* node) {
bool hasChess = false, newBoard[15][15];
memset(newBoard, false, sizeof(newBoard));
for (uint8_t i = 0; i < 15; i++)
for (uint8_t j = 0; j < 15; j++) {
if (node->board[i][j] == 0) continue;
hasChess = true;
uint8_t x1 = max(0, i - expandRadius), x2 = min(14, i + expandRadius);
uint8_t y1 = max(0, j - expandRadius), y2 = min(14, j + expandRadius);
for (uint8_t x = x1; x <= x2; x++)
for (uint8_t y = y1; y <= y2; y++)
if (node->board[x][y] == 0) newBoard[x][y] = true;
}
vector<pair<uint8_t, uint8_t>> mask;
if (!hasChess) {
mask.emplace_back(pair<uint8_t, uint8_t>(7, 7));
}
else {
for (uint8_t i = 0; i < 15; i++)
for (uint8_t j = 0; j < 15; j++)
if (newBoard[i][j])
mask.emplace_back(pair<uint8_t, uint8_t>(i, j));
}
return mask;
}
uint8_t expand_children_nodes(Node* node) {
vector<pair<uint8_t, uint8_t>> mask = get_search_nodes(node);
for (auto pos : mask) {
Node* n = new Node(node, pos.first, pos.second);
node->children.insert(n);
openTable.push_front(n);
}
return mask.size();
}
static bool is_alpha_beta_cut(Node* node) {
if (node == nullptr || node->father == nullptr) return false;
if (node->is_max_node() && node->value > node->father->value) return true;
if (!node->is_max_node() && node->value < node->father->value) return true;
return is_alpha_beta_cut(node->father);
}
static void update_value_from_node(Node* node) {
if (node == nullptr) return;
if (node->children.empty()) {
update_value_from_node(node->father);
return;
}
if (node->is_max_node()) {
int32_t cntValue = INT32_MIN;
for (Node* n : node->children)
if (n->value != INT32_MAX) cntValue = max(cntValue, n->value);
if (cntValue > node->value) {
node->value = cntValue;
update_value_from_node(node->father);
}
}
else {
int32_t cntValue = INT32_MAX;
for (Node* n : node->children)
if (n->value != INT32_MIN) cntValue = min(cntValue, n->value);
if (cntValue < node->value) {
node->value = cntValue;
update_value_from_node(node->father);
}
}
}
void set_next_pos() {
nodeNext = *nodeRoot->children.begin();
for (Node* n : nodeRoot->children)
if (n->value > nodeNext->value) nodeNext = n;
}
static void recursive_print(Node* nodeFatherPt) {
nodeFatherPt->print_info();
for (Node* nodeChildPt : nodeFatherPt->children) recursive_print(nodeChildPt);
}
void debug_print() {
nodeRoot->print_info();
for (Node* nodeChild : nodeRoot->children) recursive_print(nodeChild);
cout << endl;
}
public:
GameTree() = default;
explicit GameTree(uint32_t maxDepth, uint8_t expandRadius) : maxDepth(maxDepth), expandRadius(expandRadius) {
}
explicit GameTree(uint32_t maxDepth, uint8_t expandRadius, uint8_t(&board)[15][15]) :
maxDepth(maxDepth), expandRadius(expandRadius) {
memcpy(nodeRoot->board, board, sizeof(board));
}
uint8_t game() {
uint8_t result = nodeRoot->board_identify();
if (result == 'B') return 'B';
if (result == 'W') return 'W';
openTable.push_back(nodeRoot);
while (!openTable.empty()) {
Node* node = openTable.front();
openTable.pop_front();
closedTable.push_back(node);
if (is_alpha_beta_cut(node->father)) continue;
if (node->depth < maxDepth) {
uint8_t numExpand = expand_children_nodes(node);
if (numExpand != 0) continue;
}
node->evaluate();
update_value_from_node(node);
}
set_next_pos();
return 0;
}
pair<uint8_t, uint8_t> get_next_pos() {
if (nodeNext == nullptr)
return pair<uint8_t, uint8_t>(255, 255);
else
return pair<uint8_t, uint8_t>(nodeNext->cntX, nodeNext->cntY);
}
void show_next_pos() {
if (nodeNext == nullptr)
cout << "(255, 255)" << endl;
else
cout << "(" << (uint32_t)nodeNext->cntX << "," << (uint32_t)nodeNext->cntY << ")" << endl;
}
void show_board(bool reverse) {
if (nodeNext == nullptr) nodeNext = nodeRoot;
uint8_t row = 0;
cout << " 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4" << endl;
for (uint8_t i = 0; i < 15; i++) {
if (row < 10) cout << " ";
cout << uint32_t(row++) << " ";
for (uint8_t j = 0; j < 15; j++) {
if (j != 0) cout << "─";
if (nodeNext->board[i][j] == 'B') {
if (reverse) cout << "●"; else cout << "○";
continue;
}
if (nodeNext->board[i][j] == 'W') {
if (reverse) cout << "○"; else cout << "●";
continue;
}
if (i == 0 && j == 0) {
cout << "┌";
continue;
}
if (i == 0 && j == 14) {
cout << "┐";
continue;
}
if (i == 14 && j == 0) {
cout << "└";
continue;
}
if (i == 14 && j == 14) {
cout << "┘";
continue;
}
if (i == 0) {
cout << "┬";
continue;
}
if (i == 14) {
cout << "┴";
continue;
}
if (j == 0) {
cout << "├";
continue;
}
if (j == 14) {
cout << "┤";
continue;
}
cout << "┼";
}
cout << endl;
}
cout << endl;
}
};
/*
void machine_human_play() {
cout << endl;
uint32_t x = 0, y = 0;
uint8_t board[15][15]{};
for (uint8_t k = 0; k < 225; k++) {
GameTree gt = GameTree(9, 2, board);
uint8_t result = gt.game();
if (result == 'B') {
cout << "Black Win !" << endl;
gt.show_board(false);
return;
}
if (result == 'W') {
gt.show_board(false);
cout << "White Win !" << endl;
return;
}
gt.show_next_pos();
gt.show_board(false);
auto pos = gt.get_next_pos();
if (pos.first != 255 && pos.second != 255) board[pos.first][pos.second] = 'B';
do {
cin >> x >> y;
} while (board[x][y] != 0);
board[x][y] = 'W';
}
}
*/
// 绘制棋子
void drawChess(int x, int y, bool isBlack) {
int centerX = 30 + x * 30;
int centerY = 30 + y * 30;
setfillcolor(isBlack ? BLACK : WHITE);
solidcircle(centerX, centerY, 12); // 绘制一个棋子
}
// 绘制棋盘和棋子
void drawChessboardAndPieces(uint8_t board[15][15]) {
BeginBatchDraw();
cleardevice();
drawWinRate();//打印战绩
setlinecolor(BLACK);
for (int i = 0; i < 15; ++i) {
line(30, 30 + i * 30, WIDTH - 30, 30 + i * 30); // 绘制横线
line(30 + i * 30, 30, 30 + i * 30, HEIGHT - 30); // 绘制竖线
}
for (int i = 0; i < 15; ++i) {
for (int j = 0; j < 15; ++j) {
if (board[i][j] == 'B') {
drawChess(i, j, true); // 绘制黑色棋子
}
else if (board[i][j] == 'W') {
drawChess(i, j, false); // 绘制白色棋子
}
}
}
int centerX = 30 + my.x * 30;
int centerY = 30 + my.y * 30;
setfillcolor(RED);
solidcircle(centerX, centerY, 6); // 绘制一个棋子
EndBatchDraw();
}
/*void machine_human_play() {
cout << endl;
uint32_t x = 0, y = 0;
uint8_t board[15][15]{};
for (uint8_t k = 0; k < 225; k++) {
GameTree gt = GameTree(9, 2, board);
uint8_t result = gt.game();
settextstyle(30, 0, "宋体");
if (result == 'B') {
drawChessboardAndPieces(board); // 绘制棋盘和棋子
cout << "Black Win !" << endl;
settextcolor(GREEN);
outtextxy(180, 400, "白棋胜利!");
gt.show_board(false);
return;
}
if (result == 'W') {
drawChessboardAndPieces(board); // 绘制棋盘和棋子
gt.show_board(false);
cout << "White Win !" << endl;
settextcolor(RED);
outtextxy(180, 400, "白棋胜利!");
return;
}
gt.show_next_pos();
gt.show_board(false);
auto pos = gt.get_next_pos();
if (pos.first != 255 && pos.second != 255) board[pos.first][pos.second] = 'B';
//drawChessboard(); // 绘制棋盘
// 下面的代码用于获取鼠标点击的位置,并在界面上落子
while (true) {
drawChessboardAndPieces(board); // 绘制棋盘和棋子
MOUSEMSG msg = GetMouseMsg();
my = { msg.x/30,msg.y/30 };
if (msg.uMsg == WM_LBUTTONDOWN) {
x = msg.x / 30; // 这里假设棋盘格子的大小为30像素
y = msg.y / 30;
if (board[x][y] == 0) {
board[x][y] = 'W';
drawChess(x, y, false); // 绘制白色棋子
break;
}
}
}
}
}*/
void machine_human_play() {
cout << endl;
uint32_t x = 0, y = 0;
uint8_t board[15][15]{};
for (uint8_t k = 0; k < 225; k++) {
GameTree gt = GameTree(9, 2, board);
uint8_t result = gt.game();
settextstyle(30, 0, "宋体");
if (result == 'B') {
drawChessboardAndPieces(board); // 绘制棋盘和棋子
cout << "Black Win !" << endl;
settextcolor(GREEN);
outtextxy(180, 400, "黑棋胜利!");
gt.show_board(false);
showResultDialog(BLACK_WIN);
return;
}
if (result == 'W') {
drawChessboardAndPieces(board); // 绘制棋盘和棋子
gt.show_board(false);
cout << "White Win !" << endl;
settextcolor(RED);
outtextxy(180, 400, "白棋胜利!");
showResultDialog(WHITE_WIN);
return;
}
gt.show_next_pos();
gt.show_board(false);
auto pos = gt.get_next_pos();
if (pos.first != 255 && pos.second != 255) board[pos.first][pos.second] = 'B';
//drawChessboard(); // 绘制棋盘
// 下面的代码用于获取鼠标点击的位置,并在界面上落子
while (true) {
drawChessboardAndPieces(board); // 绘制棋盘和棋子
MOUSEMSG msg = GetMouseMsg();
my = { msg.x / 30,msg.y / 30 };
if (msg.uMsg == WM_LBUTTONDOWN) {
x = msg.x / 30; // 这里假设棋盘格子的大小为30像素
y = msg.y / 30;
if (board[x][y] == 0) {
board[x][y] = 'W';
drawChess(x, y, false); // 绘制白色棋子
break;
}
}
}
}
}
void machine_machine_play() {
cout << endl;
uint8_t turn = 'B', board[15][15]{}, inputBoard[15][15]{};
for (uint8_t k = 0; k < 225; k++) {
cout << "[" << k + 1 << "] ";
memcpy(inputBoard, board, sizeof(board));
if (turn == 'W')
for (uint8_t i = 0; i < 15; i++)
for (uint8_t j = 0; j < 15; j++) {
if (board[i][j] == 'W') inputBoard[i][j] = 'B';
if (board[i][j] == 'B') inputBoard[i][j] = 'W';
}
GameTree gt = GameTree(8, 2, inputBoard);
uint8_t result = gt.game();
if (turn == 'W' && result != 0) {
if (result == 'B') cout << "White Win !" << endl;
if (result == 'W') cout << "Black Win !" << endl;
gt.show_board(true);
return;
}
if (turn == 'B' && result != 0) {
if (result == 'B') cout << "Black Win !" << endl;
if (result == 'W') cout << "White Win !" << endl;
gt.show_board(false);
return;
}
auto pos = gt.get_next_pos();
if (turn == 'B') {
turn = 'W';
board[pos.first][pos.second] = 'B';
cout << "Black ";
gt.show_next_pos();
gt.show_board(false);
}
else {
turn = 'B';
board[pos.first][pos.second] = 'W';
cout << "White ";
gt.show_next_pos();
gt.show_board(true);
}
}
}
int main() {
initgraph(WIDTH, HEIGHT); // 初始化绘图窗口,假设棋盘大小为WxH像素
setbkcolor(GREEN);
setbkmode(1);
setlinecolor(YELLOW);
cleardevice();
machine_human_play();
_getch();
closegraph(); // 关闭绘图窗口
return 0;
}
本人是一名大学生,学艺不精,刚开始只能以这种方式呈现我的作品。谢谢大家的欣赏!!!