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

Java井字棋获胜判定代码去重优化咨询(新手求助)

Optimizing Your Tic-Tac-Toe Win Check Function

Hey there! Great job getting your Tic-Tac-Toe project up and running on Hyperskill—handling the win condition is one of the trickier parts when you're starting out, so it's smart to look for ways to clean up that repetitive code. Let's break down how to optimize this and go over some Java best practices along the way.

1. Extract Repeated Logic into a Helper Method

The biggest issue with your current code is that you're repeating the same "count X/O and check for 3 in a row" logic four separate times (horizontal, vertical, two diagonals). The fix here is to pull that common logic into a reusable helper method.

Here's a simple helper that checks if three specific board positions are all the same non-empty player:

// Helper method to check if three positions form a winning line
private String checkWinningLine(int x1, int y1, int x2, int y2, int x3, int y3) {
    String spot1 = this.field[x1][y1];
    String spot2 = this.field[x2][y2];
    String spot3 = this.field[x3][y3];

    // Check if all three spots match and aren't empty
    if (spot1.equals(spot2) && spot2.equals(spot3) && !spot1.isEmpty()) {
        return spot1 + " wins";
    }
    return null; // No winner here
}

Now you can rewrite your main determineWinner method to use this helper instead of repeating code:

public String determineWinner() {
    // Check all horizontal lines
    for (int y = 0; y <= 2; y++) {
        String result = checkWinningLine(0, y, 1, y, 2, y);
        if (result != null) {
            return result;
        }
    }

    // Check all vertical lines
    for (int x = 0; x <= 2; x++) {
        String result = checkWinningLine(x, 0, x, 1, x, 2);
        if (result != null) {
            return result;
        }
    }

    // Check both diagonals
    String diagonal1 = checkWinningLine(0, 0, 1, 1, 2, 2);
    if (diagonal1 != null) {
        return diagonal1;
    }

    String diagonal2 = checkWinningLine(0, 2, 1, 1, 2, 0);
    if (diagonal2 != null) {
        return diagonal2;
    }

    // Check for a draw
    if (this.getNumberOfMoves() == 9) {
        return "draw";
    }

    return "game not finished";
}

This cuts out all the redundant counting and condition checks, making your code shorter and easier to update later (if you ever wanted to adjust win logic, you only change the helper method).

2. Even Cleaner: Batch Check All Winning Lines

If you want to make the code even more concise, you can define all possible winning lines as a list of coordinate sets, then loop through that list to check each line:

import java.util.Arrays;
import java.util.List;

public String determineWinner() {
    // Define every possible winning line (each line is 3 (x,y) pairs)
    List<int[][]> winningLines = Arrays.asList(
        // Horizontal lines
        new int[][]{{0,0}, {1,0}, {2,0}},
        new int[][]{{0,1}, {1,1}, {2,1}},
        new int[][]{{0,2}, {1,2}, {2,2}},
        // Vertical lines
        new int[][]{{0,0}, {0,1}, {0,2}},
        new int[][]{{1,0}, {1,1}, {1,2}},
        new int[][]{{2,0}, {2,1}, {2,2}},
        // Diagonals
        new int[][]{{0,0}, {1,1}, {2,2}},
        new int[][]{{0,2}, {1,1}, {2,0}}
    );

    // Check each line for a winner
    for (int[][] line : winningLines) {
        String spot1 = this.field[line[0][0]][line[0][1]];
        String spot2 = this.field[line[1][0]][line[1][1]];
        String spot3 = this.field[line[2][0]][line[2][1]];
        
        if (spot1.equals(spot2) && spot2.equals(spot3) && !spot1.isEmpty()) {
            return spot1 + " wins";
        }
    }

    // Draw or unfinished game logic
    if (this.getNumberOfMoves() == 9) {
        return "draw";
    }
    return "game not finished";
}

This approach puts all winning lines in one place, making it super clear what you're checking, and keeps the rest of the logic tight.

3. Java Coding Best Practices to Apply

Beyond the win check, here are some general Java habits that will make your code cleaner and more maintainable:

  • Use constants for magic strings: Instead of typing "X" or "O" everywhere, define static constants. This prevents typos and makes it easy to update values later:

    private static final String PLAYER_X = "X";
    private static final String PLAYER_O = "O";
    private static final String RESULT_DRAW = "draw";
    private static final String RESULT_NOT_FINISHED = "game not finished";
    

    Then replace all direct string uses with these constants.

  • Stick to camelCase naming: Variables like countX should be xCount—this follows Java's standard naming convention (lowercase start, capitalized words for multi-names).

  • Limit variable scope: In your original code, you declared countX and countO at the top of the method, then reinitialized them in loops. It's better to declare variables inside the loop where they're used (like we did with spot1/spot2/spot3 in the helper) to avoid confusion about their values.

  • Add null checks (if needed): If your board can have null values (instead of empty strings), add a null check before comparing: spot1 != null && spot1.equals(spot2). This prevents NullPointerExceptions.

  • Follow the Single Responsibility Principle: Your determineWinner method already does one job (check the game state), which is perfect. As your project grows, keep splitting code into small, focused methods instead of making one giant method do everything.

4. Bonus: Scalable Board Idea

If you ever wanted to expand to a larger board (like 4x4 Tic-Tac-Toe), you could define the board size as a constant and generate winning lines dynamically instead of hardcoding them. For a 3x3 game, this isn't necessary, but it's a fun way to think about making your code flexible!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 16:32:49