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 ""; } }
修改细节说明
- 移除CPU逻辑:直接删掉原代码中
Random相关的所有代码,替换为玩家2的输入流程 - 输入校验优化:新增
getValidInput方法统一处理输入问题,包括数字校验、范围校验、位置占用校验 - 修复字符串bug:把原代码中
"Player "(多空格)改成"Player1","Player 2"改成"Player2",保证调用和判断一致 - 游戏结束判断:每轮玩家落子后立即检查胜负,有结果就终止循环,避免无效回合
- 符号修正:把原代码中的
'0'改成'O',符合井字棋常规符号
二、裁判功能的AOP切面实现(基于Spring AOP)
前提准备
先在Maven项目中引入Spring Context依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.20</version> </dependency>
实现步骤
重构代码,让裁判逻辑纳入Spring管理
- 给
TicTacToe类加@Component注解,变成Spring组件 - 把原有的静态变量和方法改成非静态(Spring AOP无法代理静态方法)
- 给
定义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("============="); } } }
- 配置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 { }
- 修改启动逻辑,通过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
相关产品推荐
相关产品推荐

