Java實現簡單井字棋小遊戲程式碼例項
Java第一次實驗,老師讓做一個井字棋,電腦隨機下棋。
然後就想能不能聰明一點,可以判斷出走哪一步棋;然後只能做到不會輸,還是不夠聰明,只能呆板地堵住使用者,smartRobot的第三個判斷邏輯找不到最佳位置,贏得概率比較小;而且我沒事幹時,想玩玩這個小遊戲找找成就感,但每次都會贏了機器人,所以刪刪改改了四五次,最後才成。
可以選擇誰先開始,但startGame裡的程式碼更加冗餘了。看著就很亂,但沒想到好的辦法。
smartRobot裡的程式碼全部重寫了,比原來更聰明一點了:下在四個角的位置時,能優先選擇最佳位置;然後沒有最佳位置時,再隨便找一空的(隨便找空四角位置使用for代替了,比原來更簡短)。
然後smartRobot的第一個和第三個判斷邏輯,也更聰明一點了。原來判斷機器人和判斷使用者的邏輯,是放在一個for迴圈裡的,但無法找到最佳位置,現在分開了。
機器人先開始時,才能發揮出來新新增的機器人的“小聰明”;但機器人原來的能力發揮不回來,只有使用者先開始時才能發揮出原來的能力。所以各有利弊,無論誰先開始都能適應。如果機器人先開始,並且使用者第一步棋不是下在四角的位置,那麼使用者就必輸了。其他的情況一般都是平局了。
想到一個因為可以選擇誰先開始而導致 startGame 程式碼冗餘的問題的解決方法,就是使用區域性內部類。內部類能訪問到方法的區域性物件。
主邏輯 startGame:
1. 用一個3X3的二維陣列,儲存棋盤;
2. 使用者輸入1~9下棋;
3. 判斷是否合法,不合法則重新輸入;
4. 將1~9轉換成二維的座標 x = (pos-1)/3,y = (pos-1)%3,再令二維陣列相應位置為 'O';
5. 判斷使用者是否勝利,是則退出;再判斷是否平局,是則退出;
6. 機器人下棋(根據輸入等級,呼叫不同函式);
7. 列印棋盤顯示出使用者和機器人下的棋子;
8. 判斷機器人是否勝利,是則退出;再判斷是否平局,是則退出;都不是返回第1步。
isSuccessful 判斷成功的邏輯:
判斷所有行、列、對角線是否有連成一條線的,用字元相加的和判斷即可
willBeSuccessful判斷是否將要成功:
這裡判斷的是是否有行、列有兩個相同棋子和一個空白,用字元相加的和判斷。
calculate 計算行列對角線:
使用列舉類,來判斷是計算行,還是計算列,還是計算左右對角線;計算行列時,傳入一個1~3的數字表示是哪一行那一列。
smartRobot 的第一個判斷邏輯:
如果棋子下在箭頭指向的那個位置,那麼一步棋就可勝利。
機器人先判斷自己是否有這樣一個位置,有則下在哪個地方,勝利;
方法是嘗試填入所有空白地方,每填一次,判斷一次 isSuccessful;
如果沒有,再判斷對方是否有這樣一個位置,有則堵住這個地方。
smartRobot 的第三個判斷邏輯:
如果棋子下在箭頭指向的位置,那麼再下一步必會勝利,因為下在了那個地方,第三列、第三行都是兩個棋子了,無論對方堵哪裡,都會失敗。
也是機器人先判斷自己是否有這樣一個位置,有則下;
呼叫 willBeSuccessful 判斷是否有這樣的位置。
沒有則再判斷對方是否有這樣的位置,有則堵住。
smartRobot 的第零個和第二個判斷邏輯:
處理四個角和中心的位置,如果使用者下在了中心,那麼機器人必須至少有兩個棋子下在四角位置才能保證不輸。
更改了無數次的程式碼:
import java.util.Arrays; import java.util.Scanner; public class Experiment_1 { public static void main(String[] args) { ThreeChess game = new ThreeChess(); game.startGame(); } } class ThreeChess{ private char[][] chessBoard = new char[3][3]; private int size = 0; //已經下的棋數 private final int CAPACITY = 9; //總共可下的棋數 ThreeChess(){ for(char[] line : chessBoard){ //初始化棋盤 Arrays.fill(line,' '); } } //【遊戲開始】 public void startGame(){ System.out.println("┌───┬───┬───┐"); System.out.println("│ 1 │ 2 │ 3 │"); System.out.println("├───┼───┼───┤"); System.out.println("│ 4 │ 5 │ 6 │"); System.out.println("├───┼───┼───┤"); System.out.println("│ 7 │ 8 │ 9 │"); System.out.println("└───┴───┴───┘"); System.out.println("輸入 1 ~ 9 表示要下棋的位置"); System.out.println("O是你的棋子,*是電腦的棋子"); Scanner in = new Scanner(System.in); System.out.print("選擇誰先開始:\n\t1.使用者\n\t2.機器人\nInput: "); int whoFirst = in.nextInt(); System.out.print("選擇機器人智商:\n\t1. 999+\n\t2. 250\nInput: "); int level = in.nextInt(); class Play{ //程式碼重用 //方法返回-1表示退出 int robotPlay(){ if(level == 1) smartRobot(); else sillyRobot(); printChessBroad(); if(isSuccessful() == -1) { System.out.println("機器人勝 (/ □ \\)"); return -1; }else if (size == CAPACITY){ System.out.println("==遊戲平局=="); return -1; } return 0; } int userPlay(){ int pos; while(true){ System.out.print("下棋位置: "); pos = in.nextInt(); if(pos < 1 || pos > 9 || chessBoard[(pos - 1) / 3][(pos - 1) % 3] != ' '){ System.out.println("輸入錯誤,重新輸入!"); continue; } else { chessBoard[(pos - 1)/3][(pos - 1) % 3] = 'O'; size++; break; } } if(isSuccessful() == 1){ printChessBroad(); System.out.println("恭喜,你勝了 ╰(*°▽°*)╯"); return -1; } else if(size == CAPACITY){ printChessBroad(); System.out.println("==遊戲平局=="); return -1; } return 0; } } Play play = new Play(); if(whoFirst == 2){ while(true){ //1.機器人下棋 if(play.robotPlay() == -1) return; //2.使用者下棋 if(play.userPlay() == -1) return; } } else { while(true){ //1.使用者下棋 if(play.userPlay() == -1) return; //2.機器人下棋 if(play.robotPlay() == -1) return; } } } //【機器人下棋】 private void sillyRobot(){ //笨機器人 int l,c; while(true){ l = (int)(Math.random() * 3); c = (int)(Math.random() * 3); if(chessBoard[l][c] == ' '){ chessBoard[l][c] = '*'; break; } } size++; } private int corner = 2; private void smartRobot(){ //無法戰勝的機器人 if(chessBoard[1][1] == ' '){ //搶佔中心位置 chessBoard[1][1] = '*'; size++; return; } //1.判斷是否可以下一個棋子就勝利(不能放在一起同時判斷,否則有可能錯誤最佳位置) for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ if(chessBoard[i][j] == ' '){ //【1】如果這個位置沒有棋子,就嘗試下載這個地方,看看是否可以勝; chessBoard[i][j] = '*'; if(isSuccessful() == -1){ //【1】如果勝的話,就下在這個地方了,返回即可; size++; return ; } else chessBoard[i][j] = ' '; } } } for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ //【2】邏輯同【1】 if(chessBoard[i][j] == ' '){ chessBoard[i][j] = 'O'; //【2】否則嘗試使用者下在這個位置 if(isSuccessful() == 1){ //【2】如果使用者下在這個位置會勝利,就佔領它。 chessBoard[i][j] = '*'; size++; return ; } else chessBoard[i][j] = ' '; } } } //2.如果使用者下在了中間的話,就趕緊佔兩個四角的位置,才能保證不輸。優先順序要比第一個低。使用者沒下在中間也可搶佔。 if(corner > 0){ corner--; for(int i = 0; i < 3; i++){ //優先找四邊中沒有使用者棋子的地方下 if(i == 1) continue; boolean NoBigO = true; for(int j = 0; j < 3; j++){ if(chessBoard[i][j] == 'O') NoBigO = false; } for(int j = 0; j < 3 && NoBigO; j++){ if(chessBoard[i][j] == ' '){ chessBoard[i][j] = '*'; size++; return; } } } for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ if(j == 1 || i == 1) continue; if(chessBoard[i][j] == ' '){ chessBoard[i][j] = '*'; size++; return; } } } } //end if //3.判斷是否可以下一個棋子,從而再下一步可以勝利(不能放在一起判斷) for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ if(chessBoard[i][j] == ' '){ chessBoard[i][j] = '*'; if(willBeSuccessful(-1)){ size++; return; } else chessBoard[i][j] = ' '; } } } for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ if(chessBoard[i][j] == ' '){ chessBoard[i][j] = 'O'; if (willBeSuccessful(1)) { chessBoard[i][j] = '*'; size++; return; } else chessBoard[i][j] = ' '; } } } sillyRobot(); } //【列印棋盤】 private void printChessBroad(){ System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); //模擬清屏 System.out.println("┌───┬───┬───┐"); System.out.println("│ " + chessBoard[0][0] + " │ " + chessBoard[0][1] + " │ " + chessBoard[0][2] + " │"); System.out.println("├───┼───┼───┤"); System.out.println("│ " + chessBoard[1][0] + " │ " + chessBoard[1][1] + " │ " + chessBoard[1][2] + " │"); System.out.println("├───┼───┼───┤"); System.out.println("│ " + chessBoard[2][0] + " │ " + chessBoard[2][1] + " │ " + chessBoard[2][2] + " │"); System.out.println("└───┴───┴───┘"); } //【判斷成功邏輯】 private enum Choice{ LINE,//行 COLUMN,//列 RIGHT_DIAGONAL,//右對角線 LEFT_DIAGONAL; //左對角線 } private int calculate(Choice choice,int i){ //計算行、列、對角線是否連成一條線 switch (choice){ case LINE: return chessBoard[i][0] + chessBoard[i][1] + chessBoard[i][2]; case COLUMN: return chessBoard[0][i] + chessBoard[1][i] + chessBoard[2][i]; case RIGHT_DIAGONAL: return chessBoard[0][0] + chessBoard[1][1] + chessBoard[2][2]; case LEFT_DIAGONAL: return chessBoard[0][2] + chessBoard[1][1] + chessBoard[2][0]; } return 0; } private int isSuccessful(){ /* 返回-1系統勝;返回1使用者勝;返回0表示繼續下棋。 系統勝:126 == '*' + '*' + '*' 使用者勝:237 == 'O' + 'O' + 'O' */ for(int i = 0; i < 3; i++){ if(calculate(Choice.LINE,i) == 237 || calculate(Choice.COLUMN,i) == 237) return 1; if(calculate(Choice.LINE,i) == 126 || calculate(Choice.COLUMN,i) == 126) return -1; } if(calculate(Choice.LEFT_DIAGONAL,0) == 237 || calculate(Choice.RIGHT_DIAGONAL,0) == 237) return 1; if(calculate(Choice.LEFT_DIAGONAL,0) == 126 || calculate(Choice.RIGHT_DIAGONAL,0) == 126) return -1; return 0; //繼續下棋 } private boolean willBeSuccessful(int who){ //who:-1表示判斷機器人的,+1表示判斷使用者的。 //如果行、列、對角線有2個相同棋子的個數,則將會勝, //190 == 2 * 'O' + ' ' //116 == 2 * '*' + ' ' int n = 0; int s = (who == 1) ? 190 : 116; //使用者or機器人要計算的值 for(int i = 0; i < 3; i++){ if(calculate(Choice.LINE,i) == s) n++; if(calculate(Choice.COLUMN,i) == s) n++; } //因為中心一定會被佔的,所以就不用判斷對角線了 return n > 1; } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。