C++五子棋游戏-含禁手

五子棋游戏

https://github.com/2810zhc/Simple_Gomoku

项目简介

这是一个简单的五子棋游戏,支持玩家对战、玩家与机器人对战两种模式。游戏支持计时功能,并具有判定禁手与胜负的规则。

采用了博弈树且包含基本的禁手功能(“三、三” “四、四” “长连”),考虑到了不同的禁手可能,如连续活三和跳跃活三。

功能概述

C++五子棋游戏-含禁手_第1张图片

  • 玩家对战:两个玩家轮流下棋,直到某一方获胜或棋盘满为止。
  • 人机对战:玩家与机器人进行对战,机器人自动计算落子位置。
  • 计时功能:每步棋有时间限制,每个玩家有总比赛时间。
  • 禁手规则:判断是否犯规(例如,四连禁手),并判负。
  • 胜利判断:当一方形成五个连子时,判定该玩家胜利。

游戏模式

游戏提供四种操作模式供玩家选择:

  1. 玩家对战:两名玩家在同一台计算机上进行对战。
  2. 人机对战:玩家与机器人进行对战。
  3. 规则阅读:显示五子棋的规则说明。
  4. 退出:退出游戏。

=======

部分禁手规则代码

#include "Rule.h"


bool Rule::checkWin(const Board& board, int x, int y, char stone) {
    int directions[4][2] = { {0, 1}, {1, 0}, {1, 1}, {1, -1} };//方向变换
    for (const auto& dir : directions) {
        int count = 1;
        for (int step = 1; step < 5; ++step) {
            int nx = x + step * dir[0], ny = y + step * dir[1];
            if (board.getCell(nx, ny) == stone) count++;
            else break;
        }
        for (int step = 1; step < 5; ++step) {
            int nx = x - step * dir[0], ny = y - step * dir[1];
            if (board.getCell(nx, ny) == stone) count++;
            else break;
        }
        if (count >= 5) return true;
    }
    return false;
}

bool Rule::isForbiddenMove(Board& board, int x, int y, char stone, int& liveThreeCount, int& liveFourCount) {
    if (stone != 'X') return false;  // 只有黑棋需要检测禁手
    board.removeStone(x, y);
    int temp_three = liveThreeCount;
    int flag1 = 0; int flag2 = 0;
    for (int i = 0; i < Board::SIZE; ++i) {
        for (int j = 0; j < Board::SIZE; ++j) {
            if (board.getCell(i, j) == 'X') {
               //往各个方位生长
                int x_num, k_num;
                expandInDirection(board, i, j, 1, 0, x_num, k_num);   // 下方向 (1, 0)
                if (x_num == 4 && k_num == 2) {
                    liveThreeCount++;  // 存在活三
                    flag1 = 1;
                }
                if (x_num == 5 && k_num == 2) {
                    liveFourCount++;  // 存在活四
                    flag2 = 1;
                }

                int x_num2, k_num2;
                expandInDirection(board, i, j, 0, 1, x_num2, k_num2);   // 右方向 (0, 1)
                if (x_num2 == 4 && k_num2 == 2) {
                    liveThreeCount++;  // 存在活三
                    flag1 = 1;
                }
                if (x_num2 == 5 && k_num2 == 2) {
                    liveFourCount++;  // 存在活四
                    flag2 = 1;
                }

                int x_num3, k_num3;
                expandInDirection(board, i, j, 1, 1, x_num3, k_num3);   // 右下方向 (1, 1)
                if (x_num3 == 4 && k_num3 == 2) {
                    liveThreeCount++;  // 存在活三
                    flag1 = 1;
                }
                if (x_num3 == 5 && k_num3 == 2) {
                    liveFourCount++;  // 存在活四
                    flag2 = 1;
                }

                int x_num4, k_num4;
                expandInDirection(board, i, j, 1, -1, x_num4, k_num4);  // 左下方向 (1, -1)
                if (x_num4 == 4 && k_num4 == 2) {
                    liveThreeCount++;  // 存在活三
                    flag1 = 1;
                }
                if (x_num4 == 5 && k_num4 == 2) {
                    liveFourCount++;  // 存在活四
                    flag2 = 1;
                }
            }

            else {
                //检查跳跃活三
                int x_num, k_num;
                jumpThree(board, i, j, 1, 0, x_num, k_num);   // 下方向 (1, 0)
                if (x_num == 3 && k_num == 4) {
                    liveThreeCount++;  // 存在活三
                    flag1 = 1;
                }

                int x_num2, k_num2;
                jumpThree(board, i, j, 0, 1, x_num2, k_num2);   // 右方向 (0, 1)
                if (x_num2 == 3 && k_num2 == 4) {
                    liveThreeCount++;  // 存在活三
                    flag1 = 1;
                }


                int x_num3, k_num3;
                jumpThree(board, i, j, 1, 1, x_num3, k_num3);   // 右下方向 (1, 1)
                if (x_num3 == 3 && k_num3 == 4) {
                    liveThreeCount++;  // 存在活三
                    flag1 = 1;
                }

                int x_num4, k_num4;
                jumpThree(board, i, j, 1, -1, x_num4, k_num4);  // 左下方向 (1, -1)
                if (x_num4 == 3 && k_num4 == 4) {
                    liveThreeCount++;  // 存在活三
                    flag1 = 1;
                }

            }
        }
    }
    if (flag1 == 1) {
        liveThreeCount = 1;
    }
    else {
        liveThreeCount = 0;
    }
    if (flag2 == 1) {
        liveFourCount = 1;
    }
    else {
        liveFourCount = 0;
    }

    board.placeStone(x, y,stone);
    bool count_checkline = false;
    // 检查黑棋是否存在三三禁手和四四禁手
    const int directions[8][2] = {
        {-1, 0}, {1, 0}, {0, -1}, {0, 1},  // 横、竖
        {-1, -1}, {1, 1}, {-1, 1}, {1, -1} // 对角线
    };
    for (int i = 0; i < 8; i += 2) {
        bool count_checkline_div = checkLine(board, x, y, directions[i][0], directions[i][1], stone);

        if (count_checkline_div) {
            count_checkline = true;
            std::cout << "5" << std::endl;
        }
    }

    int x_num5, k_num5;
    expandInDirection(board, x, y, 1, 0, x_num5, k_num5);   // 下方向 (1, 0)
    if (x_num5 == 4 && k_num5 == 2) {
        liveThreeCount++;  // 存在活三
    }
    if (x_num5 == 5 && k_num5 == 2) {
        liveFourCount++;  // 存在活四
    }

    int x_num6, k_num6;
    expandInDirection(board, x, y, 0, 1, x_num6, k_num6);   // 右方向 (0, 1)
    if (x_num6 == 4 && k_num6 == 2) {
        liveThreeCount++;  // 存在活三
    }
    if (x_num6 == 5 && k_num6 == 2) {
        liveFourCount++;  // 存在活四
    }

    int x_num7, k_num7;
    expandInDirection(board, x, y, 1, 1, x_num7, k_num7);   // 右下方向 (1, 1)
    if (x_num7 == 4 && k_num7 == 2) {
        liveThreeCount++;  // 存在活三
    }
    if (x_num7 == 5 && k_num7 == 2) {
        liveFourCount++;  // 存在活四
    }

    int x_num8, k_num8;
    expandInDirection(board, x, y, 1, -1, x_num8, k_num8);  // 左下方向 (1, -1)
    if (x_num8 == 4 && k_num8 == 2) {
        liveThreeCount++;  // 存在活三
    }
    if (x_num8 == 5 && k_num8 == 2) {
        liveFourCount++;  // 存在活四
    }
    if (liveThreeCount == temp_three) {
        //找到x y 【-2,2】 5*5矩阵内的‘.’
        for (int i = -2; i <= 2; ++i) {
            for (int j = -2; j <= 2; ++j) {
                int nx = x + i;
                int ny = y + j;
                if (nx == 1 && ny == 3) {
                    int x = 0;
                }
                // 检查索引是否在棋盘内
                if (nx >= 0 && nx < Board::SIZE && ny >= 0 && ny < Board::SIZE) {
                    if (board.getCell(nx, ny) == '.') {
                        // 三三禁手或四四禁手均为禁手
                        int x_num9, k_num9;
                        jumpThree(board, nx, ny, 1, 0, x_num9, k_num9);   // 下方向 (1, 0)
                        if (x_num9 == 3 && k_num9 == 4) {
                          
                            for (int i = 0; i < 3; ++i) {
                                int newX1 = nx + i * 1;
                                int newY1 = ny + i * 0;
                                int newX2 = nx - i * 1;
                                int newY2 = ny - i * 0;
                                if ((newX1 == x && newY1 == y) || (newX2 == x && newY2 == y)) {
                                    liveThreeCount++;  // 存在活三
                                }
                            }
                        }

                        int x_num10, k_num10;
                        jumpThree(board, nx, ny, 0, 1, x_num10, k_num10);   // 右方向 (0, 1)
                        if (x_num10 == 3 && k_num10 == 4) {
                            for (int i = 0; i < 3; ++i) {
                                int newX1 = nx + i * 0;
                                int newY1 = ny + i * 1;
                                int newX2 = nx - i * 0;
                                int newY2 = ny - i * 1;
                                if ((newX1 == x && newY1 == y) || (newX2 == x && newY2 == y)) {
                                    liveThreeCount++;  // 存在活三
                                }
                            }

                        }


                        int x_num11, k_num11;
                        jumpThree(board, nx, ny, 1, 1, x_num11, k_num11);   // 右下方向 (1, 1)
                        if (x_num11 == 3 && k_num11 == 4) {
                            for (int i = 0; i < 3; ++i) {
                                int newX1 = nx + i * 1;
                                int newY1 = ny + i * 1;
                                int newX2 = nx - i * 1;
                                int newY2 = ny - i * 1;
                                if ((newX1 == x && newY1 == y) || (newX2 == x && newY2 == y)) {
                                    liveThreeCount++;  // 存在活三
                                }
                            }
                        }

                        int x_num12, k_num12;
                        jumpThree(board, nx, ny, 1, -1, x_num12, k_num12);  // 左下方向 (1, -1)
                        if (x_num12 == 3 && k_num12 == 4) {
                            for (int i = 0; i < 3; ++i) {
                                int newX1 = nx + i * 1;
                                int newY1 = ny + i * -1;
                                int newX2 = nx - i * 1;
                                int newY2 = ny - i * -1;
                                if ((newX1 == x && newY1 == y) || (newX2 == x && newY2 == y)) {
                                    liveThreeCount++;  // 存在活三
                                }
                            }
                        }
                    }
                }
            }
        }
        
    }
  


    return  liveThreeCount==2 || liveFourCount==2 || count_checkline;
}

bool Rule::checkLine(const Board& board, int x, int y, int dx, int dy, char stone) {
    int count = 0;
    for (int i = -4; i <= 4; ++i) {
        int nx = x + i * dx, ny = y + i * dy;
        if (nx >= 0 && nx < Board::SIZE && ny >= 0 && ny < Board::SIZE && board.getCell(nx, ny) == stone) {
            count++;
        }
    }
    return count > 5; // 检查是否为长连
}

int Rule::countConsecutive(const Board& board, int x, int y, int dx, int dy, char stone) {
    int count = 0;
    int nx = x, ny = y;

    while (nx >= 0 && nx < Board::SIZE && ny >= 0 && ny < Board::SIZE && board.getCell(nx, ny) == stone) {
        count++;
        nx += dx;
        ny += dy;
    }


    return count;
}


void Rule::expandInDirection(const Board& board, int startX, int startY, int dx, int dy, int& x_num, int& k_num) {
    int x = startX, y = startY;
    x_num = 0;  // 初始化连续的 'X' 数量
    k_num = 0;  // 初始化空位数量

    // 向方向 (dx, dy) 扩展,直到遇到边界或棋盘上的其它棋子
    while (x >= 0 && x < Board::SIZE && y >= 0 && y < Board::SIZE) {
        char cell = board.getCell(x, y);

        if (cell == 'X') {
            // 找到连续的 'X'
            x_num++;
        }
        else if (cell == '.') {
            // 空位
            k_num++;
            break;  // 遇到空位后停止扩展
        }
        else {
            break;  // 如果遇到对方的棋子,停止扩展
        }

        // 向下一个位置扩展
        x += dx;
        y += dy;
    }

    x = startX;
    y = startY;
    while (x >= 0 && x < Board::SIZE && y >= 0 && y < Board::SIZE) {
        char cell = board.getCell(x, y);

        if (cell == 'X') {
            // 找到连续的 'X'
            x_num++;
        }
        else if (cell == '.') {
            // 空位
            k_num++;
            break;  // 遇到空位后停止扩展
        }
        else {
            break;  // 如果遇到对方的棋子,停止扩展
        }

        // 向下一个位置扩展
        x -= dx;
        y -= dy;
    }
}
void Rule::jumpThree(const Board& board, int startX, int startY, int dx, int dy, int& x_num, int& k_num) {
    int count = 0;  // 连续的对方棋子数
    int emptyCount = 0;  // 空位数

    // 检查正向(dx, dy)
    for (int i = 0; i < 4; ++i) {
        int newX = startX + i * dx;
        int newY = startY + i * dy;
        if (newX < 0 || newX >= Board::SIZE || newY < 0 || newY >= Board::SIZE) {
            continue;  // 越界,跳过
        }

        char current = board.getCell(newX, newY);
        if (current == 'X') {
            count++;  
        }
        else if (current == '.') {
            emptyCount++;  // 空位
            if (emptyCount == 2) {
                break;
            }
        }
    }


    // 检查反向(-dx, -dy)
    int count2 = 0;
    int emptyCount2 = 0;

    for (int i = 0; i < 4; ++i) {
        int newX = startX - i * dx;
        int newY = startY - i * dy;
        if (newX < 0 || newX >= Board::SIZE || newY < 0 || newY >= Board::SIZE) {
            continue;  // 越界,跳过
        }

        char current = board.getCell(newX, newY);
        if (current == 'X') {
            count2++;  // 对方棋子
        }
        else if (current == '.') {
            emptyCount2++;  // 空位
            if (emptyCount2 == 2) {
                break;
            }
        }
    }
    x_num = count2 + count;
    k_num = emptyCount2 + emptyCount;
}

你可能感兴趣的:(游戏,c++)