You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Java RMI的双人Connect4游戏checkWin()方法失效问题排查

基于Java RMI的Connect4游戏checkWin()方法故障排查与解决

核心问题分析

  1. Piece实例匹配失败:Java RMI会对序列化对象进行远程传输,服务器存储的Piece是客户端实例的序列化副本,用==判断实例相等必然失败——二者是完全独立的对象实例,即使颜色属性一致。
  2. Null引发的异常/无限循环:checkWin()中未先判断board[row][col]是否为null就调用getColor(),会触发NullPointerException;同时垂直检查逻辑存在缺陷,当整列无棋子时,row会被循环递增至等于rows,后续若未处理边界会引发逻辑错误,甚至导致循环无法终止。
  3. checkWin()逻辑低效且易出错:当前checkWin()需要自行查找棋子位置,不仅效率低,还容易因为空值处理不当引发问题。

具体修复方案

1. 修正Piece匹配逻辑,优先判断非空

永远不要用==比较远程传输的对象实例,改用颜色属性比较,且必须先检查对象是否为null:

// 错误写法
if (this.board[i][col] == currentPlayer.getPiece())

// 正确写法
if (this.board[i][col] != null && this.board[i][col].getColor().equals(currentPlayer.getColor()))

2. 传递准确棋子位置,修复checkWin()垂直检查逻辑

在updateBoard()中记录刚放置棋子的行号,直接传递给checkWin(),避免自行查找带来的错误:

// 修改updateBoard()方法,记录放置位置
@Override
public synchronized int updateBoard(int col) throws RemoteException {
    if(col >= 0 && col < columns){
        for(int row = rows - 1;row >=0;row--){
           if(this.board[row][col]==null){
               this.board[row][col] = currentPlayer.getPiece();
               int placedRow = row; // 记录刚放置的行号
               player1.updateGui(currentPlayer.getPiece(), col, this.board);
               player2.updateGui(currentPlayer.getPiece(), col, this.board);
               currentPlayer.setBoard(this.board);
               return placedRow; // 返回放置行号,-1表示失败
           }
       }
   }
   return -1;
}

修改checkWin()方法,基于已知位置检查垂直方向:

@Override
public synchronized boolean checkWin(int col, int placedRow) throws RemoteException {
    Piece currentPiece = currentPlayer.getPiece();
    if(currentPiece == null) return false;

    // 垂直检查:统计当前位置上下的连续同色棋子
    int streak = 1;
    // 向下检查(行号更大的方向,rows-1为棋盘最底部)
    for(int i = placedRow + 1; i < rows; i++){
        if(board[i][col] != null && board[i][col].getColor().equals(currentPiece.getColor())){
            streak++;
            if(streak == 4) return true;
        } else {
            break; // 连续被打断,无需继续
        }
    }
    // 向上检查(行号更小的方向)
    for(int i = placedRow - 1; i >= 0; i--){
        if(board[i][col] != null && board[i][col].getColor().equals(currentPiece.getColor())){
            streak++;
            if(streak == 4) return true;
        } else {
            break;
        }
    }

    // 此处添加水平、对角线等其他方向的检查逻辑,同样要先判断非空再比较颜色
    // ...

    return false;
}

3. 调整客户端调用逻辑

客户端的actionPerformed中,获取服务器返回的放置行号后再调用checkWin:

// 修改客户端actionPerformed方法
public void actionPerformed(ActionEvent e) {
    int column = Integer.parseInt(e.getActionCommand());
    try {
        if(myTurn){
            int placedRow = server.updateBoard(column);
            if(placedRow != -1){ 
                if(server.checkWin(column, placedRow)){
                    server.showWinner();
                }
                server.updateCurrentPlayer();
                server.updateTitle();
            }
        }
    } catch(RemoteException ex){
        ex.printStackTrace();
    }
// ....Rest of code...}

4. 全面排查空值处理

在所有涉及board数组的遍历逻辑中,必须先判断当前位置是否为null,再调用getColor()方法,彻底避免NullPointerException和逻辑错误。

内容的提问来源于stack exchange,提问作者diego alamu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 22:44:56