Java版AI五子棋游戲
本文實(shí)例為大家分享了java五子棋游戲的具體代碼,供大家參考,具體內(nèi)容如下
AI思路:通過(guò)判斷棋盤(pán)上每個(gè)空位的分?jǐn)?shù),去分?jǐn)?shù)最高的幾個(gè)點(diǎn),隨機(jī)下棋
分?jǐn)?shù)計(jì)算思路:能成5個(gè)說(shuō)明能贏了,給最高分
不能成5個(gè),對(duì)方能成5個(gè),說(shuō)明對(duì)方要贏了,給第二高分
能成活4,給第三高分
能成活3,給第四高分
能成沖4,給第五高分
能成沖3,給第六高分
能成活2,給第七高分
能成沖2,給第八高分
其他,給最低分
分?jǐn)?shù)設(shè)定可自己定義。
因?yàn)槭侨ツ陮?xiě)的了,思路記得大概就是這樣。最近根據(jù)書(shū)上寫(xiě)了個(gè)棋類游戲的設(shè)計(jì)框架,待完善后再發(fā)上來(lái),應(yīng)該會(huì)更新AI思路
下面是去年寫(xiě)的AI五子棋的代碼:
package FivechessClient; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; import java.util.Random; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; /** * * @ClassName: Game * @Description: AI五子棋 * @author xiaoxiong * @date 2015年7月3日 下午8:59:02 * */ public class Game { BufferedImage table; BufferedImage black; BufferedImage white; BufferedImage selected; /** * 棋子個(gè)數(shù) */ private static int BOARD_SIZE = 15; /** * 棋盤(pán)寬高 */ private final int TABLE_WIDTH = 535; private final int TABLE_HEIGHT = 536; /** * 棋盤(pán)15等分 */ private final int RATE = TABLE_WIDTH / BOARD_SIZE; /** * 棋盤(pán)外邊距 */ private final int X_OFFSET = 5; private final int Y_OFFSET = 6; /** * 棋盤(pán) */ private int[][] board = new int[BOARD_SIZE][BOARD_SIZE]; /** * AI分?jǐn)?shù) */ private int[][] computerScore = new int[BOARD_SIZE][BOARD_SIZE]; // private int[][] gamerScore = new int[BOARD_SIZE][BOARD_SIZE]; JFrame f = new JFrame("五子棋--小熊"); ChessBoard chessBoard = new ChessBoard(); private static int selectedX = -1; private static int selectedY = -1; private static int computerX = -1; private static int computerY = -1; private static boolean flagGamer = false; // 記錄玩家是否贏了 private static boolean flagComputer = false; // 記錄電腦是否贏了 private static int computerscore = 0; // 電腦最大分?jǐn)?shù) private static int comx, comy; // 玩家下子坐標(biāo) private final int HUO = 1; private final int CHONG = 2; private static int chesscou = 0; /** * 記錄找到的分?jǐn)?shù)一樣的棋子,隨機(jī)下這些棋子中的一個(gè),以防步法固定 */ private ArrayList<ChessXY> chessList = new ArrayList<ChessXY>(); Random rand = new Random(); /** * * @Title: initto @Description: 重置游戲 @param @return void @throws */ public void initto() { for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { board[i][j] = 0; computerScore[i][j] = 100000; } } chesscou = 0; computerX = -1; computerY = -1; flagGamer = false; flagComputer = false; } /** * * @Title: isRun @Description: 判斷該位置是否可以走 @param @param x @param @param * y @param @return @return boolean @throws */ public boolean isRun(int x, int y) { if (board[x][y] == 0) { return true; } return false; } /** * * @Title: isWin @Description: 判斷下該子是否能贏 @param @param f 顏色 @param @param x * 坐標(biāo) @param @param y @param @return @return boolean @throws */ public boolean isWin(int f, int x, int y) { int i, count = 1; boolean up, down, right, left, rup, lup, rdown, ldown; up = down = right = left = rup = lup = rdown = ldown = true; /** * * 上下 * */ for (i = 1; i < 5; ++i) { if ((y + i) < BOARD_SIZE) { if (board[x][y + i] == f && down) count++; else down = false; } if ((y - i) >= 0) { if (board[x][y - i] == f && up) count++; else up = false; } } if (count >= 5) { return true; } count = 1; /** * * 左右 * */ for (i = 1; i < 5; ++i) { if ((x + i) < BOARD_SIZE) { if (board[x + i][y] == f && right) count++; else right = false; } if ((x - i) >= 0) { if (board[x - i][y] == f && left) count++; else left = false; } } if (count >= 5) { return true; } count = 1; /** * * 左上右下 * */ for (i = 1; i < 5; ++i) { if ((x + i) < BOARD_SIZE && (y + i) < BOARD_SIZE) { if (board[x + i][y + i] == f && rdown) count++; else rdown = false; } if ((x - i) >= 0 && (y - i) >= 0) { if (board[x - i][y - i] == f && lup) count++; else lup = false; } } if (count >= 5) { return true; } count = 1; /** * * 右上左下 * */ for (i = 1; i < 5; ++i) { if ((x + i) < BOARD_SIZE && (y - i) >= 0) { if (board[x + i][y - i] == f && rup) count++; else rup = false; } if ((x - i) >= 0 && (y + i) < BOARD_SIZE) { if (board[x - i][y + i] == f && ldown) count++; else ldown = false; } } if (count >= 5) { return true; } return false; } /** * * @Title: Computer_AI @Description: AI下棋 @param @return void @throws */ public void Computer_AI() { computerscore = 0; for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { computerScore[i][j] = 0; // gamerScore[i][j] = 0; } } getScore(); for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { if (computerScore[i][j] == computerscore) { ChessXY chess = new ChessXY(i, j); chessList.add(chess); } } } int n = rand.nextInt(chessList.size()); // 電腦根據(jù)分值一樣的點(diǎn)隨機(jī)走,防止每次都走相同的步數(shù) comx = chessList.get(n).x; comy = chessList.get(n).y; chessList.clear(); } /** * * @Title: getScore @Description: 評(píng)分 @param @return void @throws */ public void getScore() { for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { if (board[i][j] == 0) { if (isWin(2, i, j)) // 電腦能贏,故給分最高,因?yàn)榭梢越Y(jié)束,所以不再檢測(cè) { computerscore = 13; computerScore[i][j] = 13; return; } else if (isWin(1, i, j)) // 電腦不能贏,玩家能贏,要阻止,所以給12分 { computerscore = 12; computerScore[i][j] = 12; } else if (isHuoOrChong(2, i, j, 4, HUO)) // 電腦玩家都不能贏,電腦能形成活四,給11分 { computerscore = (computerscore > 11 ? computerscore : 11); computerScore[i][j] = 11; } else if (isHuoOrChong(2, i, j, 4, CHONG)) // 電腦玩家都不能贏,電腦能形成沖四,給10分 { computerscore = (computerscore > 10 ? computerscore : 10); computerScore[i][j] = 10; } else if (isHuoOrChong(1, i, j, 4, HUO)) // 電腦玩家都不能贏,玩家能形成活四,給9分 { computerscore = (computerscore > 9 ? computerscore : 9); computerScore[i][j] = 9; } else if (isHuoOrChong(2, i, j, 3, HUO)) // 電腦玩家都不能贏,電腦能形成活三,給8分 { computerscore = (computerscore > 8 ? computerscore : 8); computerScore[i][j] = 8; } else if (isHuoOrChong(1, i, j, 4, CHONG)) // 電腦玩家都不能贏,玩家能形成沖四,給7分 { computerscore = (computerscore > 7 ? computerscore : 7); computerScore[i][j] = 7; } else if (isHuoOrChong(2, i, j, 3, CHONG)) // 電腦玩家都不能贏,電腦能形成沖三,給6分 { computerscore = (computerscore > 6 ? computerscore : 6); computerScore[i][j] = 6; } else if (isHuoOrChong(2, i, j, 2, HUO)) // 電腦玩家都不能贏,電腦能形成活二,給5分 { computerscore = (computerscore > 5 ? computerscore : 5); computerScore[i][j] = 5; } else if (isHuoOrChong(1, i, j, 3, CHONG)) // 電腦玩家都不能贏,玩家能形成沖三,給4分 { computerscore = (computerscore > 4 ? computerscore : 4); computerScore[i][j] = 4; } else if (isHuoOrChong(1, i, j, 2, HUO)) // 電腦玩家都不能贏,玩家能形成活二,給3分 { computerscore = (computerscore > 3 ? computerscore : 3); computerScore[i][j] = 3; } else if (isHuoOrChong(2, i, j, 2, CHONG)) // 電腦玩家都不能贏,電腦能形成沖二,給2分 { computerscore = (computerscore > 2 ? computerscore : 2); computerScore[i][j] = 2; } else if (isHuoOrChong(1, i, j, 2, CHONG)) // 電腦玩家都不能贏,玩家能形成沖二,給1分 { computerscore = (computerscore > 1 ? computerscore : 1); computerScore[i][j] = 1; } else { computerScore[i][j] = 0; } } } } } /** * * @Title: isHuoOrChong @Description: 判斷是否為活 @param @param f @param @param * x @param @param y @param @param num @param @param * hORc @param @return @return boolean @throws */ private boolean isHuoOrChong(int f, int x, int y, int num, int hORc) // 活 { num += 1; int i, count = 1; boolean terminal1 = false; boolean terminal2 = false; boolean up, down, right, left, rup, lup, rdown, ldown; up = down = right = left = rup = lup = rdown = ldown = true; /** * * 上下 * */ for (i = 1; i < num; ++i) { if ((y + i) < BOARD_SIZE) { if (board[x][y + i] == f && down) count++; else { if (board[x][y + i] == 0 && down) { terminal1 = true; } down = false; } } if ((y - i) >= 0) { if (board[x][y - i] == f && up) count++; else { if (board[x][y - i] == 0 && up) { terminal2 = true; } up = false; } } } if (count == num - 1 && hORc == HUO && terminal1 && terminal2) { return true; } if (count == num - 1 && hORc == CHONG && ((terminal1 && !terminal2) || (!terminal1 && terminal2))) { return true; } count = 1; terminal1 = false; terminal2 = false; /* 左右 */ for (i = 1; i < num; ++i) { if ((x + i) < BOARD_SIZE) { if (board[x + i][y] == f && right) count++; else { if (board[x + i][y] == 0 && right) { terminal1 = true; } right = false; } } if ((x - i) >= 0) { if (board[x - i][y] == f && left) count++; else { if (board[x - i][y] == 0 && left) { terminal2 = true; } left = false; } } } if (count == num - 1 && hORc == HUO && terminal1 && terminal2) { return true; } if (count == num - 1 && hORc == CHONG && ((terminal1 && !terminal2) || (!terminal1 && terminal2))) { return true; } count = 1; terminal1 = false; terminal2 = false; /** * * 左上右下 * */ for (i = 1; i < num; ++i) { if ((x + i) < BOARD_SIZE && (y + i) < BOARD_SIZE) { if (board[x + i][y + i] == f && rdown) count++; else { if (board[x + i][y + i] == 0 && rdown) { terminal1 = true; } rdown = false; } } if ((x - i) >= 0 && (y - i) >= 0) { if (board[x - i][y - i] == f && lup) count++; else { if (board[x - i][y - i] == 0 && lup) { terminal2 = true; } lup = false; } } } if (count == num - 1 && hORc == HUO && terminal1 && terminal2) { return true; } if (count == num - 1 && hORc == CHONG && ((terminal1 && !terminal2) || (!terminal1 && terminal2))) { return true; } count = 1; terminal1 = false; terminal2 = false; /** * * 右上左下 * */ for (i = 1; i < num; ++i) { if ((x + i) < BOARD_SIZE && (y - i) >= 0) { if (board[x + i][y - i] == f && rup) count++; else { if (board[x + i][y - i] == 0 && rup) { terminal1 = true; } rup = false; } } if ((x - i) >= 0 && (y + i) < BOARD_SIZE) { if (board[x - i][y + i] == f && ldown) count++; else { if (board[x - i][y + i] == 0 && ldown) { terminal2 = true; } ldown = false; } } } if (count == num - 1 && hORc == HUO && terminal1 && terminal2) { return true; } if (count == num - 1 && hORc == CHONG && ((terminal1 && !terminal2) || (!terminal1 && terminal2))) { return true; } return false; } public void init() throws Exception { table = ImageIO.read(new File("image/board.jpg")); black = ImageIO.read(new File("image/black.gif")); white = ImageIO.read(new File("image/white.gif")); selected = ImageIO.read(new File("image/selected.gif")); for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { board[i][j] = 0; computerScore[i][j] = 0; } } chessBoard.setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT)); chessBoard.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { int xPos = (int) ((e.getX() - X_OFFSET) / RATE); int yPos = (int) ((e.getY() - Y_OFFSET) / RATE); // System.out.println("1 " + xPos + " " + yPos); if (isRun(xPos, yPos)) { flagGamer = isWin(1, xPos, yPos); board[xPos][yPos] = 1; chesscou++; // do //電腦下棋,隨機(jī) // { // comx = (rand.nextInt(535) - X_OFFSET) / RATE; // comy = (rand.nextInt(536) - Y_OFFSET) / RATE; // } while (!isRun(comx, comy)); if (chesscou == (BOARD_SIZE * BOARD_SIZE)) { JOptionPane.showMessageDialog(null, "不相上下!?。n再來(lái)一盤(pán)吧?。。?, "結(jié)束", JOptionPane.ERROR_MESSAGE); initto(); } else { Computer_AI(); // 電腦下棋,AI算法 chesscou++; // System.out.println("2 " + comx + " " + comy); flagComputer = isWin(2, comx, comy); board[comx][comy] = 2; computerX = comx; computerY = comy; } } chessBoard.repaint(); if (flagGamer) { JOptionPane.showMessageDialog(null, "厲害厲害!?。n你贏了?。。?, "結(jié)束", JOptionPane.ERROR_MESSAGE); initto(); } else if (flagComputer) { JOptionPane.showMessageDialog(null, "哈哈哈哈?。?!\n你輸了?。?!", "結(jié)束", JOptionPane.ERROR_MESSAGE); initto(); } } public void mouseExited(MouseEvent e) { selectedX = -1; selectedY = -1; chessBoard.repaint(); } }); chessBoard.addMouseMotionListener(new MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { selectedX = (e.getX() - X_OFFSET) / RATE; selectedY = (e.getY() - Y_OFFSET) / RATE; chessBoard.repaint(); } }); f.add(chessBoard); f.setCursor(new Cursor(Cursor.HAND_CURSOR)); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setResizable(false); f.pack(); f.setVisible(true); } public static void main(String[] args) throws Exception { Game game = new Game(); game.init(); } @SuppressWarnings("serial") class ChessBoard extends JPanel { public void paint(Graphics g) { g.drawImage(table, 0, 0, null); if (selectedX >= 0 && selectedY >= 0) { g.drawImage(selected, selectedX * RATE + X_OFFSET, selectedY * RATE + Y_OFFSET, null); } if (computerX >= 0 && computerY >= 0) { g.drawImage(selected, computerX * RATE + X_OFFSET, computerY * RATE + Y_OFFSET, null); } for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { if (board[i][j] == 1) { g.drawImage(black, i * RATE + X_OFFSET, j * RATE + Y_OFFSET, null); } if (board[i][j] == 2) { g.drawImage(white, i * RATE + X_OFFSET, j * RATE + Y_OFFSET, null); } } } } } } class ChessXY { int x; int y; public ChessXY(int x, int y) { this.x = x; this.y = y; } }
更多精彩游戲,請(qǐng)參考專題《java經(jīng)典小游戲》
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用springboot單例模式與線程安全問(wèn)題踩的坑
這篇文章主要介紹了使用springboot單例模式與線程安全問(wèn)題踩的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java命令行運(yùn)行錯(cuò)誤之找不到或無(wú)法加載主類問(wèn)題的解決方法
這篇文章主要給大家介紹了關(guān)于Java命令行運(yùn)行錯(cuò)誤之找不到或無(wú)法加載主類問(wèn)題的解決方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01微信小程序獲取手機(jī)號(hào)的完整實(shí)例(Java后臺(tái)實(shí)現(xiàn))
我們?cè)谧鲂〕绦蜷_(kāi)發(fā)的過(guò)程中,經(jīng)常會(huì)涉及到用戶身份的問(wèn)題,最普遍的就是我們要獲取用戶的手機(jī)號(hào)碼,下面這篇文章主要給大家介紹了關(guān)于微信小程序獲取手機(jī)號(hào)的完整實(shí)例,后臺(tái)由Java實(shí)現(xiàn),需要的朋友可以參考下2022-06-06Java多線程編程之讀寫(xiě)鎖ReadWriteLock用法實(shí)例
這篇文章主要介紹了Java多線程編程之讀寫(xiě)鎖ReadWriteLock用法實(shí)例,本文直接給出編碼實(shí)例,需要的朋友可以參考下2015-05-05SpringCloud?Gateway詳細(xì)分析實(shí)現(xiàn)負(fù)載均衡與熔斷和限流
這篇文章主要介紹了SpringCloud?Gateway實(shí)現(xiàn)路由轉(zhuǎn)發(fā),負(fù)載均衡,熔斷和限流,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07面試JAVA時(shí),問(wèn)到spring該怎么回答
這篇文章主要介紹了Spring面試資料,學(xué)Java的小伙伴都知道Spring是面試的必問(wèn)環(huán)節(jié),看完了一天就可掌握數(shù)據(jù)結(jié)構(gòu)和算法的面試題,快來(lái)看看吧2021-08-08Spring Boot2配置服務(wù)器訪問(wèn)日志過(guò)程解析
這篇文章主要介紹了Spring Boot2配置服務(wù)器訪問(wèn)日志過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11詳解spring-boot下如何滿足多生產(chǎn)環(huán)境中個(gè)性化定制功能
這篇文章主要介紹了詳解spring-boot下如何滿足多生產(chǎn)環(huán)境中個(gè)性化定制功能,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03MyBatis中獲取Mysql數(shù)據(jù)庫(kù)插入記錄的主鍵值的實(shí)現(xiàn)
本文主要介紹了MyBatis中獲取Mysql數(shù)據(jù)庫(kù)插入記錄的主鍵值的實(shí)現(xiàn),包含了三種實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06