1、演示视频

基于Java Swing开发的五子棋游戏

2、项目截图

3. 设计说明

3.1 总体架构

项目采用面向对象的设计思想,主要包含以下核心类:

  • GomokuGame:主类,负责创建窗口、初始化UI组件、管理游戏状态(如模式、难度、步数、时间)。
  • GamePanel:继承自JPanel,是游戏的核心逻辑类,负责绘制棋盘、处理鼠标事件、管理棋盘状态、执行AI逻辑。

3.2 数据结构

  • int[][] board:二维数组,大小为15x15,用于存储棋盘状态(0=空,1=黑棋,2=白棋)。
  • int[][][] cachedScores:三维数组,用于缓存每个位置在每个方向上的棋型分数,是性能优化的关键。
  • List<Point> chessList:列表,记录所有已落子的位置,用于悔棋和标记最后一步。
  • Deque<Integer> history:双端队列,记录每一步的棋子总数,用于悔棋时恢复状态。

3.3 性能优化

项目在AI评估函数方面进行了多项性能优化,以确保在中级和高级难度下AI能够快速响应:

  • 缓存机制:使用 cachedScores 数组缓存每个位置的棋型分数。每次落子后,只需更新受影响区域的缓存,避免了每次评估时都重新计算整个棋盘的复杂度。
  • 局部搜索:在 evaluateBoard 和 findPossibleMoves 方法中,只评估和搜索棋子附近的区域,而非整个棋盘,大大减少了计算量。
  • 位运算存储:在 getPatternScore 中,将AI和玩家的分数存储在同一个整数的高低16位中,提高了内存访问和数据处理效率。

4. 算法说明

4.1 胜负判定算法

胜负判定采用中心扩展法。当一个棋子落下后,程序会以该棋子为中心,检查四个方向(水平、垂直、两个对角线)上连续同色棋子的数量。如果任一方向达到或超过5个,则判定该颜色的玩家获胜。

private boolean checkWin(int row, int col) {
    int player = board[row][col];
    return (countConnectedStones(row, col, 1, 0, player) >= 5 || // 水平
            countConnectedStones(row, col, 0, 1, player) >= 5 || // 垂直
            countConnectedStones(row, col, 1, 1, player) >= 5 || // 右下对角
            countConnectedStones(row, col, 1, -1, player) >= 5);  // 右上对角
}

4.2 AI评估函数

AI的决策基于一个综合评估函数,该函数计算棋盘上每个空位对AI的价值。评估值由三部分组成:

  • 位置权重:中心位置权重更高,边缘位置权重较低。
  • 棋型分数:评估在该位置落子后形成的棋型(如活三、活四、冲四等)带来的价值。
  • 攻防平衡:AI不仅考虑自己的进攻得分,也考虑阻止对手的防守得分。

评估函数利用缓存的棋型分数,避免了重复计算,显著提升了性能。

4.3 AI搜索算法

  • 初级 (贪心):遍历所有空位,计算每个位置的评估得分,选择得分最高的位置落子。
  • 中级 (Minimax):使用Minimax算法,递归搜索未来几步的棋局,模拟AI和玩家的轮流下棋,选择能获得最大收益的移动。搜索深度为2。
  • 高级 (Alpha-Beta剪枝):在Minimax基础上引入Alpha-Beta剪枝技术,通过剪除无效分支来减少搜索节点,提高搜索效率。搜索深度为3。

5. 测试说明

5.1 功能测试

  • 界面测试:验证窗口、按钮、标签、下拉框等UI组件是否正常显示和响应。
  • 落子测试:验证鼠标点击是否能正确转换为棋盘坐标并放置棋子。
  • 模式切换测试:验证双人模式和人机模式之间的切换是否正常。
  • 难度切换测试:验证AI难度选择和算法信息显示是否正确。
  • 悔棋测试:验证在不同模式下悔棋功能是否按预期工作(双人模式悔一步,人机模式悔两步)。
  • 胜负判定测试:手动构建五子连线场景,验证胜负判定是否准确。

5.2 性能测试

  • AI响应时间:在中级和高级难度下,测试AI下棋的响应时间,确保在可接受范围内(通常小于1秒)。
  • 内存使用:监控程序运行时的内存占用,确保没有内存泄漏。
  • CPU占用:在AI思考时监控CPU占用率,确保算法优化有效。

5.3 边界测试

  • 棋盘边界:测试在棋盘边缘落子的行为。
  • 游戏结束:测试游戏结束后,点击棋盘、悔棋等操作是否被正确阻止。
  • 模式切换:测试在游戏进行中切换模式的行为。

6. 关键代码

6.1 棋盘状态管理

private int[][] board = new int[BOARD_SIZE][BOARD_SIZE];
private List<Point> chessList = new ArrayList<>();
private Deque<Integer> history = new ArrayDeque<>();

6.2 AI评估函数核心

private int evaluatePosition(int row, int col) {
    int positionValue = POSITION_WEIGHTS[row][col];
    int score = 0;
    int aiScore = 0;
    int playerScore = 0;

    for (int d = 0; d < 4; d++) {
        int cachedValue = cachedScores[row][col][d];
        aiScore += cachedValue & 0xFFFF;
        playerScore += (cachedValue >> 16) & 0xFFFF;
    }

    score = (int)(aiScore * 1.0 + playerScore * 0.9) + positionValue;
    return score;
}

6.3 棋型分数缓存与更新

private int getPatternScore(int row, int col, int direction) {
    // ... (棋型分析逻辑) ...
    return (playerPatternScore << 16) | (aiPatternScore & 0xFFFF);
}

private void updateCachedScores(int row, int col) {
    int range = 4;
    for (int r = Math.max(0, row - range); r < Math.min(BOARD_SIZE, row + range + 1); r++) {
        for (int c = Math.max(0, col - range); c < Math.min(BOARD_SIZE, col + range + 1); c++) {
            for (int d = 0; d < 4; d++) {
                cachedScores[r][c][d] = getPatternScore(r, c, d);
            }
        }
    }
}

6.4 Alpha-Beta剪枝算法

private int[] findBestMoveWithAlphaBeta(int depth) {
    // ... (初始化) ...
    List<Point> possibleMoves = findPossibleMoves();

    for (Point p : possibleMoves) {
        // ... (尝试移动) ...
        int score = alphaBeta(depth - 1, alpha, beta, false);
        // ... (撤销移动) ...

        if (score > bestScore) {
            bestScore = score;
            bestRow = i;
            bestCol = j;
            alpha = Math.max(alpha, score);
            if (beta <= alpha) { // Beta剪枝
                break;
            }
        }
    }
    return new int[]{bestRow, bestCol};
}

6.5 悔棋逻辑

public void undoLastMove() {
    if (GomokuGame.this.isPVPMode) {
        if (!chessList.isEmpty()) {
            Point lastPoint = chessList.remove(chessList.size() - 1);
            board[lastPoint.y][lastPoint.x] = 0;
            updateCachedScores(lastPoint.y, lastPoint.x);
            isBlackTurn = !isBlackTurn;
            GomokuGame.this.moveCount = Math.max(0, GomokuGame.this.moveCount - 1);
        }
    } else {
        if (isBlackTurn && chessList.size() >= 2) {
            Point aiPoint = chessList.remove(chessList.size() - 1);
            board[aiPoint.y][aiPoint.x] = 0;
            updateCachedScores(aiPoint.y, aiPoint.x);

            Point humanPoint = chessList.remove(chessList.size() - 1);
            board[humanPoint.y][humanPoint.x] = 0;
            updateCachedScores(humanPoint.y, humanPoint.x);

            GomokuGame.this.moveCount = Math.max(0, GomokuGame.this.moveCount - 2);
        }
    }
    // ... (更新UI) ...
}

本项目代码结构清晰,注释详细,性能优化得当,是一个功能完整、易于理解和扩展的五子棋游戏实现。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐