加上了AI,总算是可以玩了。不过目前的AI只会消极防守,玩家和电脑都不能赢的时候AI只会随机下,好在棋盘小,所以这个问题不算太大。
大概也不会继续完善了吧……都是重复工作,学不了什么新东西。就是练练脑子。
AI还是让琪琪点醒的,“如果发现要赢了就堵住”,我原来的想法是想办法遍历棋局找出二连的棋子,都想到脑子疼了。明明反过来思考一下,如果往一个地方落子之后有人能赢,那这个地方不就是关键位置么,这样最多九次就能找到答案了。
留了一个找不出问题所在的小bug,随手用笨方法堵上了。
另外还是不知道怎么把无限while循环里面的Scanner关掉……虽然只是警告不是错误,但是看着还是很不爽啊……
1 package ticTacToeII; 2 3 public class Client { 4 public static void main(String[] args) { 5 Game game = new Game(); 6 Player player = new Player(); 7 Computer computer = new Computer(); 8 9 while (true) { 10 game.printChessBoard(); 11 12 player.move(game); 13 System.out.println(); 14 if (game.checkWin()) { 15 game.printChessBoard(); 16 System.out.println("你赢了!!!!!!!赢了啊啊啊啊啊啊啊啊啊啊啊啊!!!!"); 17 break; 18 } 19 if (game.isFilled()) { 20 game.printChessBoard(); 21 System.out.println("平局了。"); 22 break; 23 } 24 25 System.out.print("电脑落子:"); 26 27 computer.move(game); 28 if (game.checkWin()) { 29 System.out.println(); // 奇怪的bug,如果电脑赢了会出现打印错误,暂时用这个方法修补。 30 game.printChessBoard(); 31 System.out.println("电脑赢了!!!!!!!赢了啊啊啊啊啊啊啊啊啊啊啊啊!!!!"); 32 break; 33 } 34 if (game.isFilled()) { 35 game.printChessBoard(); 36 System.out.println("平局了。"); 37 break; 38 } 39 40 System.out.println(); 41 } 42 } 43 44 /** 测试用跟踪方法。*/ 45 protected static void trace(String toShow) { 46 System.out.printf("===Traceback:%s=== ", toShow); 47 } 48 }
1 package ticTacToeII; 2 3 class Game { 4 private String chessBoard; 5 private String[][] pieces = new String[3][3]; 6 7 /** 初始化棋盘样式和棋子数组。*/ 8 public Game() { 9 chessBoard = 10 "-------------- " + 11 "| %s | %s | %s | " + 12 "-------------- " + 13 "| %s | %s | %s | " + 14 "-------------- " + 15 "| %s | %s | %s | " + 16 "-------------- "; 17 18 for (String[] s1: pieces) { 19 for (int i = 0; i < s1.length; i++) 20 s1[i] = " "; 21 } 22 } 23 24 /** 在棋盘上落子。*/ 25 int changeBoard(int row, int column, String chessMan) { 26 if (this.pieces[row][column] == " ") { 27 this.pieces[row][column] = chessMan; 28 return 1; 29 } 30 return -1; 31 } 32 33 /** 棋子数组降维。*/ 34 private String[] pieceList() { 35 String[] temp = new String[9]; 36 for (int i = 0, j = 0; i < 3; i++, j += 3) 37 System.arraycopy(this.pieces[i], 0, temp, j, 3); 38 return temp; 39 } 40 41 /** 打印棋盘。*/ 42 void printChessBoard() { 43 System.out.printf(this.chessBoard, (Object[])this.pieceList()); 44 } 45 46 /** 判断平局。*/ 47 boolean isFilled() { 48 for (String[] s1: this.pieces) { 49 for (String s2: s1) { 50 if (s2 == " ") 51 return false; 52 } 53 } 54 return true; 55 } 56 /** 判断胜利。*/ 57 boolean checkWin() { 58 for (int i = 0; i < 3; i++) { 59 if ((this.pieces[i][0] == this.pieces[i][1] && 60 this.pieces[i][1] == this.pieces[i][2] && 61 this.pieces[i][1] != " ") 62 || 63 (this.pieces[0][i] == this.pieces[1][i] && 64 this.pieces[1][i] == this.pieces[2][i] && 65 this.pieces[1][i] != " ")) 66 return true; 67 } 68 if ((this.pieces[0][0] == this.pieces[1][1] && 69 this.pieces[1][1] == this.pieces[2][2] && 70 this.pieces[1][1] != " ") 71 || 72 (this.pieces[2][0] == this.pieces[1][1] && 73 this.pieces[1][1] == this.pieces[0][2] && 74 this.pieces[1][1] != " ")) 75 return true; 76 77 return false; 78 } 79 80 /** 方法重载,接受一个棋子数组的拷贝,判断此情况下能否胜利。*/ 81 boolean checkWin(String[][] list) { 82 for (int i = 0; i < 3; i++) { 83 if ((list[i][0] == list[i][1] && 84 list[i][1] == list[i][2] && 85 list[i][1] != " ") 86 || 87 (list[0][i] == list[1][i] && 88 list[1][i] == list[2][i] && 89 list[1][i] != " ")) 90 return true; 91 } 92 if ((list[0][0] == list[1][1] && 93 list[1][1] == list[2][2] && 94 list[1][1] != " ") 95 || 96 (list[2][0] == list[1][1] && 97 list[1][1] == list[0][2] && 98 list[1][1] != " ")) 99 return true; 100 101 return false; 102 } 103 104 /** 返回一个棋子数组的拷贝。*/ 105 String[][] piecesCopy() { 106 String[][] copy = new String[3][3]; 107 for (int i = 0; i < 3; i++) { 108 for (int j = 0; j < 3; j++) { 109 copy[i][j] = this.pieces[i][j]; 110 } 111 } 112 return copy; 113 } 114 }
1 package ticTacToeII; 2 3 class Computer { 4 5 /** 电脑落子。*/ 6 void move(Game game) { 7 int row, column; 8 9 // 如果有关键点就落在那。 10 if (getCriticalPoint(game)[0] != -1) { 11 row = getCriticalPoint(game)[0]; 12 column = getCriticalPoint(game)[1]; 13 game.changeBoard(row, column, "×"); 14 return; 15 } 16 17 // 否则就随机产生位置。 18 while (true) { 19 row = (int) (Math.random() * 3); 20 column = (int) (Math.random() * 3); 21 if (game.changeBoard(row, column, "×") == -1) 22 continue; 23 break; 24 } 25 } 26 27 /** 找出并返回棋盘上的关键点。*/ 28 private int[] getCriticalPoint(Game game) { 29 int[] coordinate = {-1, -1}; 30 String[][] copy = game.piecesCopy(); 31 String[] chessman = {"×", "○"}; // 顺序反了的话即使能赢也会优先堵玩家。 32 String temp; 33 34 // 拷贝棋盘并遍历,找出落子后能胜利的点,不管是哪一方胜利。 35 for (int i = 0; i < 3; i++) { 36 for (int j = 0; j < 3; j++) { 37 for (String s: chessman) { 38 if (copy[i][j] != " ") // 位置占用了就直接跳过不废话。 39 continue; 40 temp = copy[i][j]; 41 copy[i][j] = s; 42 if (game.checkWin(copy)) { 43 coordinate[0] = i; 44 coordinate[1] = j; 45 return coordinate; 46 } 47 copy[i][j] = temp; 48 } 49 } 50 } 51 return coordinate; 52 } 53 }
1 package ticTacToeII; 2 3 class Player { 4 5 /** 玩家落子。*/ 6 @SuppressWarnings("resource") 7 void move(Game game) { 8 9 while (true) { 10 java.util.Scanner input = new java.util.Scanner(System.in); 11 12 System.out.print("请输入行数(1-3):"); 13 String row = input.next(); 14 if (!isValid(row)) 15 continue; 16 System.out.print("请输入列数(1-3):"); 17 String column = input.next(); 18 if (!isValid(column)) 19 continue; 20 21 int r = Integer.parseInt(row) - 1; 22 int c = Integer.parseInt(column) - 1; 23 24 if (game.changeBoard(r, c, "○") == -1) { 25 System.out.println("这里有子了。 "); 26 continue; 27 } 28 29 return; 30 } 31 } 32 33 /** 检查玩家输入。*/ 34 private boolean isValid(String userInput) { 35 if (userInput.matches("[123]{1}")) 36 return true; 37 else 38 return false; 39 } 40 }