Deepseek实现五子棋对局,实现人机对战

使用AI对话,给出基础需求

AI帮助提炼需求,并自动生成图片

实现菜单

新游戏

悔棋

人人对战

人机对战(算法优化)

Java Swing包实现,识别准确,渐变背景
在这里插入图片描述

package org.example.gobang;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Stack;
import java.awt.BorderLayout;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class Gobang extends JPanel {
    // 游戏参数
    private static final int BOARD_SIZE = 15;
    private static final int CELL_SIZE = 40;
    private static final int MARGIN = 40;

    // 游戏状态
    private int[][] board = new int[BOARD_SIZE][BOARD_SIZE];
    private int currentPlayer = 1; // 1: 黑棋 2: 白棋
    private boolean gameOver = false;
    private boolean vsAI = false;    // 人机对战模式
    private Stack<int[]> moveHistory = new Stack<>(); // 棋步历史
    private final int MAX_UNDO = 3;  // 最大悔棋次数
    private int undoCount = 0;       // 当前悔棋计数
    private JPanel controlPanel;
    
    // 属性变更支持
    private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
    
    // 历史对局相关
    private ArrayList<int[]> replayMoves = new ArrayList<>(); // 复盘时使用的棋步
    private int replayIndex = 0; // 当前复盘索引
    private boolean replayMode = false; // 是否处于复盘模式
    private Timer replayTimer; // 复盘定时器
    private JFrame parentFrame; // 父窗口引用

    public Gobang() {
        this(null);
    }
    
    public Gobang(JFrame parent) {
        this.parentFrame = parent;
        
        // 初始化控制面板 - 移至顶部
        controlPanel = new JPanel();
        controlPanel.setBackground(new Color(243, 224, 195));
        controlPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        controlPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 5));
        
        // 创建顶部按钮
        JButton restartBtn = createStyledButton("新游戏");
        String playerType = (currentPlayer == 1) ? "黑方" : "白方";
        JButton undoBtn = createStyledButton(playerType + "悔棋(剩余" + (MAX_UNDO - undoCount) + "次)");
        JCheckBox aiModeCheck = createStyledCheckBox("人机对战");
        
        // 事件监听器
        restartBtn.addActionListener(e -> {
            resetGame();
            undoBtn.setText("黑方悔棋(剩余" + MAX_UNDO + "次)");
        });
        
        undoBtn.addActionListener(e -> {
            if (undoCount < MAX_UNDO && !moveHistory.isEmpty()) {
                int[] lastMove = moveHistory.pop();
                board[lastMove[0]][lastMove[1]] = 0;
                currentPlayer = lastMove[2]; // 恢复上一个玩家
                propertyChangeSupport.firePropertyChange("currentPlayer", 0, currentPlayer);
                undoCount++;
                // 确保显示的是当前玩家类型
                String playerType1 = (currentPlayer == 1) ? "黑方" : "白方";
                undoBtn.setText(playerType1 + "悔棋(剩余" + (MAX_UNDO - undoCount) + "次)");
                repaint();
            }
        });
        
        aiModeCheck.addItemListener(e -> {
            vsAI = (e.getStateChange() == ItemEvent.SELECTED);
            resetGame();
        });
        
        // 添加按钮到控制面板
        controlPanel.add(restartBtn);
        controlPanel.add(undoBtn);
        controlPanel.add(aiModeCheck);
        
        setPreferredSize(new Dimension(
                CELL_SIZE*(BOARD_SIZE-1) + 2*MARGIN,
                CELL_SIZE*(BOARD_SIZE-1) + 2*MARGIN
        ));
        
        // 初始化复盘定时器
        replayTimer = new Timer(1000, e -> {
            if (replayIndex < replayMoves.size()) {
                int[] move = replayMoves.get(replayIndex++);
                board[move[0]][move[1]] = move[2];
                repaint();
            } else {
                replayTimer.stop();
                JOptionPane.showMessageDialog(this, "复盘结束");
            }
        });

        // 鼠标监听器
        addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (replayMode) {
                    return; // 复盘模式下不响应鼠标点击
                }
                
                if (!gameOver) {
                    int x = e.getX() - MARGIN;
                    int y = e.getY() - MARGIN;
                    int i = (x + CELL_SIZE/2) / CELL_SIZE;
                    int j = (y + CELL_SIZE/2) / CELL_SIZE;

                    if (i >= 0 && i < BOARD_SIZE && 
                        j >= 0 && j < BOARD_SIZE && 
                        board[i][j] == 0) {
                        moveHistory.push(new int[]{i, j, currentPlayer});
                        board[i][j] = currentPlayer;
                        
                        if (checkWin(i, j)) {
                            gameOver = true;
                            repaint();
                            String winner = (currentPlayer == 1 ? "黑方" : "白方");
                            JOptionPane.showMessageDialog(Gobang.this, winner + "获胜!");
                            
                            // 询问是否保存对局
                            int option = JOptionPane.showConfirmDialog(Gobang.this, 
                                "是否保存本局对战记录?", "保存对局", 
                                JOptionPane.YES_NO_OPTION);
                            if (option == JOptionPane.YES_OPTION) {
                                saveGame(); 
                            }
                        } else {
                            int oldPlayer = currentPlayer;
                            currentPlayer = currentPlayer == 1 ? 2 : 1;
                            propertyChangeSupport.firePropertyChange("currentPlayer", oldPlayer, currentPlayer);
                            repaint();
                            
                            // AI回合处理
                            if (!gameOver && vsAI && currentPlayer == 2) {
                                makeAIMove();
                            }
                        }
                    }
                }
            }
        });
    }

    // 添加属性变更监听器
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }
    
    // 添加特定属性变更监听器
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
    }
    
    // 移除属性变更监听器
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }
    
    // 移除特定属性变更监听器
    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
    }

    private void resetGame() {
        board = new int[BOARD_SIZE][BOARD_SIZE];
        int oldPlayer = currentPlayer;
        currentPlayer = 1;
        gameOver = false;
        moveHistory.clear();
        undoCount = 0;
        propertyChangeSupport.firePropertyChange("currentPlayer", oldPlayer, currentPlayer);
        repaint();
    }

    private void makeAIMove() {
        double bestScore = Integer.MIN_VALUE;
        int bestI = -1, bestJ = -1;
        boolean foundWinningMove = false;

        // 首先检查是否有直接获胜的位置
        for (int i = 0; i < BOARD_SIZE && !foundWinningMove; i++) {
            for (int j = 0; j < BOARD_SIZE && !foundWinningMove; j++) {
                if (board[i][j] == 0) {
                    // 临时落子检查是否获胜
                    board[i][j] = 2;
                    if (checkWin(i, j)) {
                        bestI = i;
                        bestJ = j;
                        foundWinningMove = true;
                    }
                    board[i][j] = 0; // 恢复
                }
            }
        }

        // 如果没有直接获胜的位置,再评估最佳位置
        if (!foundWinningMove) {
            for (int i = 0; i < BOARD_SIZE; i++) {
                for (int j = 0; j < BOARD_SIZE; j++) {
                    if (board[i][j] == 0) {
                        // 评估这个位置的分数
                        double score = evaluatePosition(i, j);
                        if (score > bestScore) {
                            bestScore = score;
                            bestI = i;
                            bestJ = j;
                        }
                    }
                }
            }
        }

        // 在最佳位置落子
        if (bestI != -1 && bestJ != -1) {
            moveHistory.push(new int[]{bestI, bestJ, currentPlayer});
            board[bestI][bestJ] = currentPlayer;
            if (checkWin(bestI, bestJ)) {
                gameOver = true;
                repaint();
                JOptionPane.showMessageDialog(null, "白方获胜!");
            } else {
                int oldPlayer = currentPlayer;
                currentPlayer = 1;
                propertyChangeSupport.firePropertyChange("currentPlayer", oldPlayer, currentPlayer);
                repaint();
            }
        }
    }

    private double evaluatePosition(int x, int y) {
        int score = 0;
        int[][] directions = {{1,0}, {0,1}, {1,1}, {1,-1}};

        // 检查AI自己可以连成五子的机会 - 最高优先级
        board[x][y] = 2; // 临时落子
        if (checkWin(x, y)) {
            board[x][y] = 0; // 恢复
            return 1000000; // 极大提高必胜位置权重,确保AI选择获胜位置
        }
        
        // 检查是否需要防守(对手是否可以在这里连成五子)
        board[x][y] = 1;
        if (checkWin(x, y)) {
            board[x][y] = 0;
            return 195000; // 大幅提高防守权重,接近进攻权重
        }
        
        // 检查是否是中间位置的连子威胁(对手在中间位置形成连子)
        boolean isCentralPosition = isCentralPosition(x, y);
        if (isCentralPosition) {
            // 检查中间位置的连子威胁
            int centralThreatLevel = checkCentralThreat(x, y, 1);
            if (centralThreatLevel > 0) {
                board[x][y] = 0;
                return centralThreatLevel * 7.0; // 提高中间位置连子的防守权重
            }
        }

        // 检查对手的潜在威胁
        int threatLevel = checkThreatLevel(x, y, 1);
        if (threatLevel > 0) {
            board[x][y] = 0;
            // 对角线方向的威胁更危险,需要更高的防守权重
            boolean isDiagonalThreat = isDiagonalThreat(x, y, 1);
            double threatMultiplier = isDiagonalThreat ? 6.0 : 5.0; // 大幅提高防守权重
            return threatLevel * threatMultiplier; // 提高威胁应对权重
        }

        // 检查AI的进攻机会
        int aiThreatLevel = checkThreatLevel(x, y, 2);
        if (aiThreatLevel > 0) {
            board[x][y] = 0;
            // 对角线方向的进攻更有效
            boolean isDiagonalThreat = isDiagonalThreat(x, y, 2);
            double aiThreatMultiplier = isDiagonalThreat ? 5.5 : 4.8;
            // 检查是否靠近边界,如果是则降低进攻权重
            if (isNearBoundary(x, y)) {
                aiThreatMultiplier *= 0.7; // 降低边界附近的进攻权重
            }
            return aiThreatLevel * aiThreatMultiplier; // 更积极的进攻权重
        }
        board[x][y] = 0;

        // 评估每个方向的连子情况
        for (int[] dir : directions) {
            int dx = dir[0], dy = dir[1];
            boolean isDiagonal = Math.abs(dx) == Math.abs(dy);
            // 提高对角线方向的权重
            double defenseMultiplier = isDiagonal ? 6.5 : 4.5; // 大幅提高斜向防守权重
            double attackMultiplier = isDiagonal ? 6.0 : 4.0; // 提高斜向进攻权重
            // 平衡进攻和防守,但略微倾向防守
            score += evaluateDirection(x, y, dx, dy, 2) * attackMultiplier;
            score += evaluateDirection(x, y, dx, dy, 1) * defenseMultiplier;
        }

        // 优化中心位置和关键点位置权重
        int centerWeight = 50 - (Math.abs(x - BOARD_SIZE/2) + Math.abs(y - BOARD_SIZE/2));
        score += centerWeight * 6; // 进一步提高中心控制的重要性

        // 考虑周围棋子的影响
        score += evaluateSurroundings(x, y) * 2.5; // 提高周围环境评估权重

        return score;
    }
    
    // 检查是否是对角线方向的威胁
    private boolean isDiagonalThreat(int x, int y, int player) {
        int[][] diagonalDirections = {{1,1}, {1,-1}};
        
        for (int[] dir : diagonalDirections) {
            int dx = dir[0], dy = dir[1];
            int threat = checkDirectionalThreat(x, y, dx, dy, player);
            if (threat > 0) {
                return true;
            }
        }
        
        return false;
    }
    
    // 检查是否是中间位置
    private boolean isCentralPosition(int x, int y) {
        // 定义中间区域范围(棋盘的中间区域,大约是3-11的范围)
        int minCentral = 3;
        int maxCentral = BOARD_SIZE - 4; // 11 for 15x15 board
        return x >= minCentral && x <= maxCentral && y >= minCentral && y <= maxCentral;
    }
    
    // 检查是否靠近边界
    private boolean isNearBoundary(int x, int y) {
        // 定义边界范围(距离边缘2格以内)
        int boundaryThreshold = 2;
        return x <= boundaryThreshold || x >= BOARD_SIZE - 1 - boundaryThreshold || 
               y <= boundaryThreshold || y >= BOARD_SIZE - 1 - boundaryThreshold;
    }
    
    // 检查中间位置的连子威胁
    private int checkCentralThreat(int x, int y, int player) {
        int maxThreat = 0;
        int[][] directions = {{1,0}, {0,1}, {1,1}, {1,-1}};
        
        // 检查是否在中间位置形成连子
        for (int[] dir : directions) {
            int dx = dir[0], dy = dir[1];
            int centralCount = countCentralPieces(x, y, dx, dy, player);
            
            // 如果在中间位置有3个或更多连子,这是一个高威胁
            if (centralCount >= 3) {
                int threatScore = centralCount * 25000; // 中间连子威胁基础分数
                maxThreat = Math.max(maxThreat, threatScore);
            }
        }
        
        return maxThreat;
    }
    
    // 计算中间位置的连子数量
    private int countCentralPieces(int x, int y, int dx, int dy, int player) {
        int count = 1; // 包括当前位置
        
        // 正向检查
        int tx = x + dx, ty = y + dy;
        while (tx >= 0 && tx < BOARD_SIZE && ty >= 0 && ty < BOARD_SIZE && isCentralPosition(tx, ty)) {
            if (board[tx][ty] == player) {
                count++;
            } else {
                break;
            }
            tx += dx;
            ty += dy;
        }
        
        // 反向检查
        tx = x - dx;
        ty = y - dy;
        while (tx >= 0 && tx < BOARD_SIZE && ty >= 0 && ty < BOARD_SIZE && isCentralPosition(tx, ty)) {
            if (board[tx][ty] == player) {
                count++;
            } else {
                break;
            }
            tx -= dx;
            ty -= dy;
        }
        
        return count;
    }
    
    private int evaluateSurroundings(int x, int y) {
        int score = 0;
        int[][] directions = {{-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,1}, {1,-1}, {1,0}, {1,1}};
        int aiCount = 0;
        int playerCount = 0;
        int emptyCount = 0;
        int diagonalAiCount = 0;
        int diagonalPlayerCount = 0;
        
        // 检查周围8个方向的棋子分布
        for (int[] dir : directions) {
            int nx = x + dir[0];
            int ny = y + dir[1];
            boolean isDiagonal = Math.abs(dir[0]) == 1 && Math.abs(dir[1]) == 1;
            
            if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE) {
                if (board[nx][ny] == 1) {
                    playerCount++;
                    if (isDiagonal) diagonalPlayerCount++;
                } else if (board[nx][ny] == 2) {
                    aiCount++;
                    if (isDiagonal) diagonalAiCount++;
                } else {
                    emptyCount++;
                }
            }
        }
        
        // 根据周围棋子分布评分
        // 如果周围有己方棋子,增加权重
        if (aiCount > 0) {
            score += aiCount * 250; // 提高己方棋子权重
            // 对角线方向的己方棋子额外加分
            score += diagonalAiCount * 100;
        }
        
        // 如果周围有对方棋子,增加防守权重
        if (playerCount > 0) {
            score += playerCount * 300; // 大幅提高防守权重
            // 对角线方向的对方棋子额外加分
            score += diagonalPlayerCount * 180; // 提高对角线防守权重
        }
        
        // 如果周围有空位,增加灵活性权重
        score += emptyCount * 60;
        
        // 如果周围同时有己方和对方棋子,这是一个交汇点,增加权重
        if (aiCount > 0 && playerCount > 0) {
            score += 400; // 提高交汇点权重
            // 如果对角线上有交汇,额外加分
            if (diagonalAiCount > 0 && diagonalPlayerCount > 0) {
                score += 200;
            }
        }
        
        return score;
    }



    private int evaluateDirection(int x, int y, int dx, int dy, int player) {
        int count = 1;
        int space = 0;
        int score = 0;
        int maxSpace = 2;
        boolean isDiagonal = Math.abs(dx) == 1 && Math.abs(dy) == 1;
        int consecutiveCount = 1;
        boolean isLive = true;
        boolean hitBoundary = false;

        // 正向检查
        int tx = x + dx, ty = y + dy;
        while (tx >= 0 && tx < BOARD_SIZE && ty >= 0 && ty < BOARD_SIZE && space <= maxSpace) {
            if (board[tx][ty] == player) {
                count++;
                consecutiveCount++;
            } else if (board[tx][ty] == 0) {
                space++;
                consecutiveCount = 0;
            } else {
                isLive = false;
                break;
            }
            tx += dx;
            ty += dy;
        }
        
        // 检查反向是否碰到边界
        if (tx < 0 || tx >= BOARD_SIZE || ty < 0 || ty >= BOARD_SIZE) {
            hitBoundary = true;
        }

        // 反向检查
        tx = x - dx;
        ty = y - dy;
        int reverseConsecutive = 1; // 反向连续计数
        while (tx >= 0 && tx < BOARD_SIZE && ty >= 0 && ty < BOARD_SIZE && space <= maxSpace) {
            if (board[tx][ty] == player) {
                count++;
                reverseConsecutive++;
            } else if (board[tx][ty] == 0) {
                space++;
                consecutiveCount = 0;
            } else {
                isLive = false;
                break;
            }
            tx -= dx;
            ty -= dy;
        }
        
        // 取最大连续值
        consecutiveCount = Math.max(consecutiveCount, reverseConsecutive);

        // 根据连子数量、空位和活度评分
        if (count >= 4) {
            score = isLive ? 20000 : 10000; // 进一步提高活四和冲四权重
        } else if (count == 3) {
            if (space >= 2) { // 活三
                score = isLive ? 8000 : 4000; // 大幅提高活三权重
            } else { // 眠三
                score = 2000; // 提高眠三权重
            }
        } else if (count == 2) {
            if (space >= 2) { // 活二
                score = isLive ? 1500 : 600; // 提高活二权重
            } else { // 眠二
                score = 300; // 提高眠二权重
            }
        } else {
            score = space >= 2 ? 150 : 30; // 提高基础权重
        }

        // 斜向加权
        if (isDiagonal) {
            score = (int)(score * 1.8); // 进一步增加斜向权重
            if ((x == 0 || x == BOARD_SIZE-1) && (y == 0 || y == BOARD_SIZE-1)) {
                score = (int)(score * 1.5); // 提高斜角权重
            }
        }
        
        // 如果碰到边界,降低评分权重
        if (hitBoundary) {
            // 如果是进攻方(AI),边界情况下降低权重更多
            if (player == 2) {
                score = (int)(score * 0.6); // 边界情况下大幅降低AI进攻权重
            } else {
                score = (int)(score * 0.8); // 边界情况下适当降低防守权重
            }
        }
        
        // 根据连续性额外加分
        if (consecutiveCount >= 3) {
            score += consecutiveCount * 500; // 连续棋子额外加分
        }

        return score;
    }



    private int checkThreatLevel(int x, int y, int player) {
        int maxThreat = 0;
        int[][] directions = {{1,0}, {0,1}, {1,1}, {1,-1}};

        // 检查每个方向的威胁
        for (int[] dir : directions) {
            int dx = dir[0], dy = dir[1];
            int threat = checkDirectionalThreat(x, y, dx, dy, player);
            maxThreat = Math.max(maxThreat, threat);
        }

        return maxThreat;
    }

    private int checkDirectionalThreat(int x, int y, int dx, int dy, int player) {
        int count = 1;
        int emptyBefore = 0;
        int emptyAfter = 0;
        boolean isBlocked = false;
        boolean hitBoundary = false;
        int consecutiveCount = 1; // 连续棋子计数

        // 向一个方向检查
        int tx = x + dx, ty = y + dy;
        while (tx >= 0 && tx < BOARD_SIZE && ty >= 0 && ty < BOARD_SIZE) {
            if (board[tx][ty] == player) {
                count++;
                consecutiveCount++;
            } else if (board[tx][ty] == 0) {
                emptyAfter++;
                consecutiveCount = 0;
                break;
            } else {
                isBlocked = true;
                break;
            }
            tx += dx;
            ty += dy;
        }
        
        // 检查是否碰到边界
        if (tx < 0 || tx >= BOARD_SIZE || ty < 0 || ty >= BOARD_SIZE) {
            hitBoundary = true;
        }

        // 向相反方向检查
        tx = x - dx;
        ty = y - dy;
        int reverseConsecutive = 1; // 反向连续计数
        while (tx >= 0 && tx < BOARD_SIZE && ty >= 0 && ty < BOARD_SIZE) {
            if (board[tx][ty] == player) {
                count++;
                reverseConsecutive++;
            } else if (board[tx][ty] == 0) {
                emptyBefore++;
                break;
            } else {
                isBlocked = true;
                break;
            }
            tx -= dx;
            ty -= dy;
        }
        
        // 取最大连续值
        consecutiveCount = Math.max(consecutiveCount, reverseConsecutive);

        // 评估威胁等级
        if (count >= 4) {
            return hitBoundary ? 50000 : 70000; // 边界情况下降低连四威胁权重
        } else if (count == 3) {
            // 区分活三和眠三
            if (emptyBefore + emptyAfter >= 2) {
                // 活三威胁
                boolean isDiagonal = Math.abs(dx) == Math.abs(dy);
                int baseScore = isBlocked ? 25000 : 40000; // 提高活三威胁权重
                // 对角线方向的活三威胁更危险
                // 如果碰到边界,降低威胁评估
                if (hitBoundary) {
                    baseScore = (int)(baseScore * 0.6);
                }
                return isDiagonal ? (int)(baseScore * 1.5) : baseScore;
            } else {
                // 眠三威胁
                return hitBoundary ? 9000 : 15000; // 边界情况下降低眠三威胁权重
            }
        } else if (count == 2 && emptyBefore + emptyAfter >= 2) {
            // 活二威胁
            boolean isDiagonal = Math.abs(dx) == Math.abs(dy);
            int baseScore = isBlocked ? 8000 : 12000; // 提高活二威胁权重
            // 连续的活二比不连续的更危险
            if (consecutiveCount >= 2) {
                baseScore = (int)(baseScore * 1.3);
            }
            // 如果碰到边界,降低威胁评估
            if (hitBoundary) {
                baseScore = (int)(baseScore * 0.5);
            }
            return isDiagonal ? (int)(baseScore * 1.4) : baseScore;
        }

        return 0;
    }
    

    private boolean checkWin(int x, int y) {
        int[][] directions = {{1,0}, {0,1}, {1,1}, {1,-1}};
        for (int[] dir : directions) {
            int count = 1;
            int dx = dir[0], dy = dir[1];

            // 正向检查
            int tx = x + dx, ty = y + dy;
            while (tx >= 0 && tx < BOARD_SIZE &&
                    ty >= 0 && ty < BOARD_SIZE &&
                    board[tx][ty] == currentPlayer) {
                count++;
                tx += dx;
                ty += dy;
            }

            // 反向检查
            tx = x - dx; ty = y - dy;
            while (tx >= 0 && tx < BOARD_SIZE &&
                    ty >= 0 && ty < BOARD_SIZE &&
                    board[tx][ty] == currentPlayer) {
                count++;
                tx -= dx;
                ty -= dy;
            }

            if (count >= 5) return true;
        }
        return false;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制渐变背景
        GradientPaint gradient = new GradientPaint(
            0, 0, new Color(243, 224, 195),
            getWidth(), getHeight(), new Color(212, 167, 106)
        );
        g2d.setPaint(gradient);
        g2d.fillRect(0, 0, getWidth(), getHeight());

        // 绘制网格线
        g2d.setColor(new Color(139, 69, 19, 180));
        g2d.setStroke(new BasicStroke(1.0f));
        for (int i = 0; i < BOARD_SIZE; i++) {
            int pos = MARGIN + i * CELL_SIZE;
            g2d.drawLine(MARGIN, pos, MARGIN + (BOARD_SIZE-1)*CELL_SIZE, pos);
            g2d.drawLine(pos, MARGIN, pos, MARGIN + (BOARD_SIZE-1)*CELL_SIZE);
        }

        // 绘制棋子
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (board[i][j] != 0) {
                    int x = MARGIN + i*CELL_SIZE - CELL_SIZE/2 + 2;
                    int y = MARGIN + j*CELL_SIZE - CELL_SIZE/2 + 2;
                    int size = CELL_SIZE - 4;

                    // 绘制棋子阴影
                    g2d.setColor(new Color(0, 0, 0, 50));
                    g2d.fillOval(x + 2, y + 2, size, size);

                    // 绘制棋子本体
                    Color pieceColor = board[i][j] == 1 ? Color.BLACK : Color.WHITE;
                    GradientPaint pieceGradient = new GradientPaint(
                        x, y, pieceColor,
                        x + size, y + size,
                        board[i][j] == 1 ? new Color(40, 40, 40) : new Color(220, 220, 220)
                    );
                    g2d.setPaint(pieceGradient);
                    g2d.fillOval(x, y, size, size);

                    // 绘制棋子高光
                    if (board[i][j] == 2) {
                        g2d.setColor(new Color(255, 255, 255, 100));
                        g2d.fillOval(x + size/4, y + size/4, size/4, size/4);
                    }
                }
            }
        }
    }

    // 创建样式化按钮
    private JButton createStyledButton(String text) {
        JButton button = new JButton(text);
        button.setFont(new Font("微软雅黑", Font.BOLD, 14));
        button.setBackground(new Color(205, 133, 63));
        button.setForeground(Color.WHITE);
        button.setFocusPainted(false);
        button.setBorder(BorderFactory.createRaisedBevelBorder());
        return button;
    }
    
    // 创建样式化复选框
    private JCheckBox createStyledCheckBox(String text) {
        JCheckBox checkBox = new JCheckBox(text);
        checkBox.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        checkBox.setBackground(new Color(243, 224, 195));
        checkBox.setFocusPainted(false);
        return checkBox;
    }
    
    // 保存游戏记录到文件
    private void saveGame() {
        try {
            // 创建保存对话框
            JFileChooser fileChooser = new JFileChooser();
            fileChooser.setDialogTitle("保存对局记录");
            
            // 设置默认文件名(使用当前时间)
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
            String defaultFileName = "gobang_" + sdf.format(new Date()) + ".txt";
            fileChooser.setSelectedFile(new File(defaultFileName));
            
            // 显示保存对话框
            int userSelection = fileChooser.showSaveDialog(parentFrame);
            
            if (userSelection == JFileChooser.APPROVE_OPTION) {
                File fileToSave = fileChooser.getSelectedFile();
                
                // 如果文件已存在,询问是否覆盖
                if (fileToSave.exists()) {
                    int response = JOptionPane.showConfirmDialog(parentFrame,
                            "文件已存在,是否覆盖?", "确认覆盖",
                            JOptionPane.YES_NO_OPTION,
                            JOptionPane.QUESTION_MESSAGE);
                    if (response != JOptionPane.YES_OPTION) {
                        return;
                    }
                }
                
                // 写入文件
                try (PrintWriter writer = new PrintWriter(new FileWriter(fileToSave))) {
                    // 写入游戏信息头
                    writer.println("五子棋对局记录");
                    writer.println("时间: " + sdf.format(new Date()));
                    writer.println("模式: " + (vsAI ? "人机对战" : "双人对战"));
                    writer.println("胜方: " + (currentPlayer == 1 ? "黑方" : "白方"));
                    writer.println("棋谱:");
                    
                    // 写入棋谱(将moveHistory转换为ArrayList以便按顺序访问)
                    ArrayList<int[]> moves = new ArrayList<>(moveHistory);
                    for (int i = 0; i < moves.size(); i++) {
                        int[] move = moves.get(i);
                        writer.println((i+1) + ". " + (char)('A' + move[0]) + (move[1] + 1) + 
                                " " + (move[2] == 1 ? "黑" : "白"));
                    }
                    
                    JOptionPane.showMessageDialog(parentFrame, 
                            "对局记录已保存至: " + fileToSave.getAbsolutePath(), 
                            "保存成功", JOptionPane.INFORMATION_MESSAGE);
                }
            }
        } catch (IOException e) {
            JOptionPane.showMessageDialog(parentFrame, 
                    "保存失败: " + e.getMessage(), 
                    "错误", JOptionPane.ERROR_MESSAGE);
        }
    }

    // 添加主方法,作为程序入口点
    public static void main(String[] args) {
        JFrame frame = new JFrame("五子棋");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        // 创建菜单栏
        JMenuBar menuBar = new JMenuBar();
        
        // 游戏菜单
        JMenu gameMenu = new JMenu("游戏");
        gameMenu.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        JMenuItem newGameItem = new JMenuItem("新游戏");
        JMenuItem exitItem = new JMenuItem("退出");
        gameMenu.add(newGameItem);
        gameMenu.addSeparator();
        gameMenu.add(exitItem);
        
        // 设置菜单
        JMenu settingsMenu = new JMenu("设置");
        settingsMenu.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        JCheckBoxMenuItem aiModeItem = new JCheckBoxMenuItem("人机对战");
        settingsMenu.add(aiModeItem);
        
        // 历史菜单
        JMenu historyMenu = new JMenu("历史对局");
        historyMenu.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        JMenuItem loadGameItem = new JMenuItem("加载对局");
        JMenuItem historyListItem = new JMenuItem("历史记录");
        historyMenu.add(loadGameItem);
        historyMenu.add(historyListItem);
        
        // 添加菜单到菜单栏
        menuBar.add(gameMenu);
        menuBar.add(settingsMenu);
        menuBar.add(historyMenu);
        
        // 设置菜单事件
        newGameItem.addActionListener(e -> {
            Gobang gobang = (Gobang)frame.getContentPane().getComponent(0);
            gobang.resetGame();
        });
        
        exitItem.addActionListener(e -> System.exit(0));
        
        aiModeItem.addActionListener(e -> {
            Gobang gobang = (Gobang)frame.getContentPane().getComponent(0);
            gobang.vsAI = aiModeItem.isSelected();
            gobang.resetGame();
        });
        
        loadGameItem.addActionListener(e -> {
            JOptionPane.showMessageDialog(frame, "加载对局功能即将推出", "提示", JOptionPane.INFORMATION_MESSAGE);
        });
        
        historyListItem.addActionListener(e -> {
            JOptionPane.showMessageDialog(frame, "历史记录功能即将推出", "提示", JOptionPane.INFORMATION_MESSAGE);
        });
        
        // 设置菜单栏
        frame.setJMenuBar(menuBar);
        
        Gobang gobang = new Gobang(frame);
        frame.setLayout(new BorderLayout());
        frame.add(gobang, BorderLayout.CENTER);
        frame.add(gobang.controlPanel, BorderLayout.NORTH); // 控制面板移至顶部
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}


    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值