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

Java将CPU对战井字棋改为双人模式并实现裁判AOP切面求助

井字棋双人对战改造与AOP裁判切面实现方案

一、CPU对战改双人对战的修改方案

核心修改点

  • 删掉CPU随机生成位置的逻辑,换成玩家2手动输入位置
  • 修复原代码里的字符串匹配bug(placePiece方法中"Player "多空格、"Player 2"和调用时的"Player2"不匹配)
  • 增加输入合法性校验:必须是1-9的数字,且位置未被占用

修改后的完整代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class TicTacToe {

    static ArrayList<Integer> player1Positions = new ArrayList<>();
    static ArrayList<Integer> player2Positions = new ArrayList<>();

    public static void main(String[] args) {
        char[][] gameBoard = {
                {' ', '|', ' ', '|', ' '},
                {'-', '+', '-', '+', '-'},
                {' ', '|', ' ', '|', ' '},
                {'-', '+', '-', '+', '-'},
                {' ', '|', ' ', '|', ' '}
        };

        Scanner scan = new Scanner(System.in);
        printGameBoard(gameBoard);

        while (true) {
            // 玩家1回合
            int playerPos = getValidInput(scan, "玩家1,请输入你的位置(1-9):");
            placePiece(gameBoard, playerPos, "Player1");
            printGameBoard(gameBoard);
            String result = checkWinner();
            if (!result.isEmpty()) {
                System.out.println(result);
                break;
            }

            // 玩家2回合
            int player2Pos = getValidInput(scan, "玩家2,请输入你的位置(1-9):");
            placePiece(gameBoard, player2Pos, "Player2");
            printGameBoard(gameBoard);
            result = checkWinner();
            if (!result.isEmpty()) {
                System.out.println(result);
                break;
            }
        }
        scan.close();
    }

    // 统一处理输入校验,避免重复代码
    private static int getValidInput(Scanner scan, String prompt) {
        int pos;
        while (true) {
            System.out.println(prompt);
            // 校验输入是否为整数
            while (!scan.hasNextInt()) {
                System.out.println("请输入有效的数字(1-9)!");
                scan.next(); // 清除无效输入
            }
            pos = scan.nextInt();
            // 校验位置范围和占用情况
            if (pos < 1 || pos > 9) {
                System.out.println("位置必须在1-9之间!");
            } else if (player1Positions.contains(pos) || player2Positions.contains(pos)) {
                System.out.println("该位置已被占用,请重新选择!");
            } else {
                break;
            }
        }
        return pos;
    }

    public static void printGameBoard(char[][] gameBoard) {
        for (char[] row : gameBoard) {
            for (char c : row) {
                System.out.print(c);
            }
            System.out.println();
        }
    }

    public static void placePiece(char[][] gameBoard, int pos, String user) {
        char symbol = ' ';
        if (user.equals("Player1")) {
            symbol = 'X';
            player1Positions.add(pos);
        } else if (user.equals("Player2")) {
            symbol = 'O';
            player2Positions.add(pos);
        }

        switch (pos) {
            case 1: gameBoard[0][0] = symbol; break;
            case 2: gameBoard[0][2] = symbol; break;
            case 3: gameBoard[0][4] = symbol; break;
            case 4: gameBoard[2][0] = symbol; break;
            case 5: gameBoard[2][2] = symbol; break;
            case 6: gameBoard[2][4] = symbol; break;
            case 7: gameBoard[4][0] = symbol; break;
            case 8: gameBoard[4][2] = symbol; break;
            case 9: gameBoard[4][4] = symbol; break;
            default: break;
        }
    }

    public static String checkWinner() {
        List<Integer> topRow = Arrays.asList(1, 2, 3);
        List<Integer> middleRow = Arrays.asList(4, 5, 6);
        List<Integer> bottomRow = Arrays.asList(7, 8, 9);
        List<Integer> leftColumn = Arrays.asList(1, 4, 7);
        List<Integer> middleColumn = Arrays.asList(2, 5, 8);
        List<Integer> rightColumn = Arrays.asList(3, 6, 9);
        List<Integer> cross1 = Arrays.asList(1, 5, 9);
        List<Integer> cross2 = Arrays.asList(7, 5, 3);

        List<List<Integer>> winning = new ArrayList<>();
        winning.add(topRow);
        winning.add(middleRow);
        winning.add(bottomRow);
        winning.add(leftColumn);
        winning.add(middleColumn);
        winning.add(rightColumn);
        winning.add(cross1);
        winning.add(cross2);

        for (List<Integer> l : winning) {
            if (player1Positions.containsAll(l)) {
                return "恭喜玩家1获胜!";
            } else if (player2Positions.containsAll(l)) {
                return "恭喜玩家2获胜!";
            }
        }

        if (player1Positions.size() + player2Positions.size() == 9) {
            return "平局!";
        }

        return "";
    }
}

修改细节说明

  1. 移除CPU逻辑:直接删掉原代码中Random相关的所有代码,替换为玩家2的输入流程
  2. 输入校验优化:新增getValidInput方法统一处理输入问题,包括数字校验、范围校验、位置占用校验
  3. 修复字符串bug:把原代码中"Player "(多空格)改成"Player1","Player 2"改成"Player2",保证调用和判断一致
  4. 游戏结束判断:每轮玩家落子后立即检查胜负,有结果就终止循环,避免无效回合
  5. 符号修正:把原代码中的'0'改成'O',符合井字棋常规符号

二、裁判功能的AOP切面实现(基于Spring AOP)

前提准备

先在Maven项目中引入Spring Context依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.20</version>
</dependency>

实现步骤

  1. 重构代码,让裁判逻辑纳入Spring管理

    • 给TicTacToe类加@Component注解,变成Spring组件
    • 把原有的静态变量和方法改成非静态(Spring AOP无法代理静态方法)
  2. 定义AOP切面类

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class GameRefereeAspect {

    // 切点:匹配TicTacToe类的checkWinner方法
    @AfterReturning(pointcut = "execution(* com.example.TicTacToe.checkWinner(..))", returning = "result")
    public void recordGameResult(JoinPoint joinPoint, String result) {
        if (!result.isEmpty()) {
            System.out.println("=== 裁判记录 ===");
            System.out.println("比赛结果:" + result);
            System.out.println("=============");
        } else {
            System.out.println("=== 裁判判定 ===");
            System.out.println("比赛继续,未分出胜负");
            System.out.println("=============");
        }
    }
}
  1. 配置Spring启用AOP
    • 创建配置类,添加@EnableAspectJAutoProxy注解:
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
  1. 修改启动逻辑,通过Spring容器获取Bean
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        TicTacToe game = context.getBean(TicTacToe.class);
        game.startGame(); // 把原main方法中的游戏逻辑移到startGame实例方法中
        context.close();
    }
}

关键说明

  • @AfterReturning通知:在checkWinner方法执行完并返回结果后触发,用来记录裁判的判定结果
  • 切点表达式:execution(* com.example.TicTacToe.checkWinner(..)) 匹配指定类的checkWinner方法,*表示任意返回值,..表示任意参数
  • 非静态改造:Spring AOP不支持代理静态方法,所以必须把原静态成员改成实例成员

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:35:17