C++之五子棋人机对战模式

#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;
}
本人是一名大学生,学艺不精,刚开始只能以这种方式呈现我的作品。谢谢大家的欣赏!!!

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值