Java五子棋AI實(shí)現(xiàn)代碼
思路:
- ①五子棋界面的實(shí)現(xiàn)
- ②交互下棋的實(shí)現(xiàn)
- ③重繪
- ④AI,實(shí)現(xiàn)人機(jī)對(duì)戰(zhàn)
五子棋和簡單AI的實(shí)現(xiàn):
首先將五子棋的界面寫出來。
首先我們寫一個(gè)接口類,定義好棋盤的數(shù)據(jù)(目的是方便修改)。
public interface Config {
public static final int X0=50;//左上角起點(diǎn)X值
public static final int Y0=50;//左上角起點(diǎn)Y值
public static final int ROWS=15;//橫向線數(shù)
public static final int COLUMNS=15;//縱向線數(shù)
public static final int CHESSSIZE=40;//棋子直徑
public static final int SIZE=50;//單元格大小
}
再來寫五子棋的界面。寫界面的方法和畫圖板是一樣的。
public class FiveChessUI extends JFrame implements Config {
static FiveChessUI fcUI = new FiveChessUI();
public static void main(String[] args){
fcUI.initUI();
}
private int [][] chesses = new int[ROWS][COLUMNS];//創(chuàng)建一個(gè)二維數(shù)組用來標(biāo)記棋盤上的位置
/**
* 初始化五子棋窗體的方法
*/
public void initUI(){
ChessListener listener = new ChessListener(chesses,fcUI);
this.setTitle("五子棋v1.0");
this.setSize(900, 800);//設(shè)置界面尺寸
this.setResizable(false);//界面不可改變大小
this.setLocationRelativeTo(null);//設(shè)置界面居中
this.setDefaultCloseOperation(3);//設(shè)置退出進(jìn)程
BorderLayout bl = new BorderLayout();//設(shè)置界面布局為窗體式布局
this.setLayout(bl);
JPanel jp = new JPanel();
jp.setPreferredSize(new Dimension(100,0));
this.add(jp,BorderLayout.EAST);
String [] name ={"重新開始","黑棋先下","白棋先下","悔棋","人機(jī)對(duì)戰(zhàn)","人人對(duì)戰(zhàn)"};
for(int i=0;i<name.length;i++){//依次給按鈕添加動(dòng)作監(jiān)聽,這里用循環(huán)可減少代碼
JButton jbu = new JButton(name[i]);
jbu.setPreferredSize(new Dimension(95,30));
jp.add(jbu);
jbu.addActionListener(listener);
}
this.setVisible(true);//設(shè)置可見
listener.gr = this.getGraphics();
this.addMouseListener(listener);//給界面加上鼠標(biāo)監(jiān)聽
}
/**
* 重寫繪制窗體的方法
*/
public void paint(Graphics g){
super.paint(g);
//在重繪的同時(shí)繪制棋盤
drawChessTable(g);
//在重繪的同時(shí)繪制棋子
drawChess(g);
}
public void drawChess(Graphics g){
ImageIcon bai = new ImageIcon("C:\\Users\\Administrator\\Pictures\\五子棋\\baizi.png");//添加白子圖片
ImageIcon hei = new ImageIcon("C:\\Users\\Administrator\\Pictures\\五子棋\\heizi.png");//添加黑子圖片
for(int i=0;i<chesses.length;i++){
for(int j=0;j<chesses.length;j++){
if(chesses[i][j]==1){
g.drawImage(hei.getImage(), X0 + SIZE * i - Config.CHESSSIZE / 2, Y0 + SIZE * j - Config.CHESSSIZE / 2, Config.CHESSSIZE,
Config.CHESSSIZE, null);
}else if(chesses[i][j]==-1){
g.drawImage(bai.getImage(), X0 + SIZE * i - Config.CHESSSIZE / 2, Y0 + SIZE * j - Config.CHESSSIZE / 2, Config.CHESSSIZE,
Config.CHESSSIZE, null);
}
}
}
}
public void drawChessTable(Graphics g){
//添加背景圖片
ImageIcon img= new ImageIcon("C:\\Users\\Administrator\\Pictures\\chesstable.jpg");
g.drawImage(img.getImage(), 0, 0, 800, 800,null);
//畫棋盤橫線
for(int i=0;i<ROWS;i++){
g.drawLine(X0, Y0+i*SIZE, X0+(COLUMNS-1)*SIZE, Y0+i*SIZE);
}
//畫棋盤豎線
for(int j=0;j<Config.COLUMNS;j++){
g.drawLine(X0+j*SIZE, Y0, X0+j*SIZE,Y0+(ROWS-1)*SIZE );
}
}
}
監(jiān)聽器類代碼如下:
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
public class ChessListener extends MouseAdapter implements Config, ActionListener {
public Graphics gr;
private int count = 0;// 計(jì)數(shù)器
private int[][] chesses;// 創(chuàng)建一個(gè)二維數(shù)組用來存放棋子的坐標(biāo)
private String name;
private int t, r;
private int cl = 0, AI=2;
private int i, j, x, y, z = 0, w = 0,zz=0,ww=0;
private FiveChessUI fc;// 聲明FiveChessUI類的一個(gè)對(duì)象
private int setX[] = new int[ROWS * COLUMNS];// 創(chuàng)建一維數(shù)組setX[]
private int setY[] = new int[ROWS * COLUMNS];// 創(chuàng)建一維數(shù)組setY[]
private int[][] chessValue = new int[ROWS][COLUMNS];
private int index = 0;// 創(chuàng)建數(shù)組的下標(biāo)
HashMap<String, Integer> hm = new HashMap<String, Integer>();//創(chuàng)建權(quán)值表
public ChessListener(int[][] chesses, FiveChessUI fc) {
this.fc = fc;
this.chesses = chesses;
//權(quán)值設(shè)置,這個(gè)需要自己慢慢調(diào),小編寫的一般,AI有時(shí)會(huì)出問題
hm.put("1", 20);
hm.put("11", 60);
hm.put("111", 200);
hm.put("1111", 1000);
hm.put("-1", 20);
hm.put("-1-1", 60);
hm.put("-1-1-1", 200);
hm.put("-1-1-1-1", 1000);
hm.put("1-1", 20);
hm.put("11-1", 30);
hm.put("111-1", 80);
hm.put("1111-1", 1000);
hm.put("-11", 20);
hm.put("-111", 30);
hm.put("-1111", 80);
hm.put("-11111", 1000);
hm.put("1-1", 20);
hm.put("-1-11", 30);
hm.put("-1-1-11", 80);
hm.put("-1-1-1-11", 1000);
hm.put("1-1", 20);
hm.put("1-1-1", 30);
hm.put("1-1-1-1", 80);
hm.put("1-1-1-1-1", 1000);
}
public void mouseReleased(MouseEvent e) {
// 得到鼠標(biāo)事件發(fā)生的時(shí)候光標(biāo)的位置
int x1 = e.getX();
int y1 = e.getY();
// 按行遍歷棋盤,坐標(biāo)(i,j)
for (j = 0; j < ROWS; j++) {
for (i = 0; i < ROWS; i++) {// 得到交叉點(diǎn)的坐標(biāo)
x = X0 + SIZE * i;// 橫坐標(biāo)
y = Y0 + SIZE * j;// 縱坐標(biāo)
// 與圓心的誤差為size/3
if (x1 > x - SIZE * 5 / 12 && x1 < x + SIZE * 5 / 12 && y1 > y - SIZE * 5 / 12
&& y1 < y + SIZE * 5 / 12) {
ImageIcon bai = new ImageIcon("C:\\Users\\Administrator\\Pictures\\baizi5.png");
ImageIcon hei = new ImageIcon("C:\\Users\\Administrator\\Pictures\\heizi4.png");
if (AI == 0) { // 人人對(duì)戰(zhàn)
if (chesses[i][j] == 0) {// 如果選的位置沒有棋子
if (count == 0) {
chesses[i][j] = 1;// 如果是黑子,就為1
count++;
gr.drawImage(hei.getImage(), X0 + SIZE * i - CHESSSIZE / 2,
Y0 + SIZE * j - CHESSSIZE / 2, CHESSSIZE, CHESSSIZE, null);
cl = 0;
} else {
chesses[i][j] = -1;// 如果是白子就為-1
count--;
gr.drawImage(bai.getImage(), X0 + SIZE * i - CHESSSIZE / 2,
Y0 + SIZE * j - CHESSSIZE / 2, CHESSSIZE, CHESSSIZE, null);
cl = 1;
}
setX[index] = i;// 將下的棋子的橫坐標(biāo)存入setX[]
setY[index] = j;// 將下的棋子的縱坐標(biāo)存入setY[]
index++;// 存入一個(gè)坐標(biāo),一維數(shù)組角標(biāo)加1
// 以交叉點(diǎn)畫圓
checkRow(i, j);
z = 1;
w = 1;
return;
}
}
if (AI == 1) { // 人機(jī)對(duì)戰(zhàn)
if (chesses[i][j] == 0) {// 如果選的位置沒有棋子
if (count == 0) {
// 玩家下棋
chesses[i][j] = 1;// 如果是黑子,就為1
// count++;
gr.drawImage(hei.getImage(), X0 + SIZE * i - CHESSSIZE / 2,
Y0 + SIZE * j - CHESSSIZE / 2, CHESSSIZE, CHESSSIZE, null);
cl = 0;
count++;
checkRow(i, j);//判斷是否勝利
setX[index] = i;// 將下的棋子的橫坐標(biāo)存入setX[]
setY[index] = j;// 將下的棋子的縱坐標(biāo)存入setY[]
index++;// 存入一個(gè)坐標(biāo),一維數(shù)組角標(biāo)加1
}
this.AI();
if (count == 1) {
// 輸出所有點(diǎn)的權(quán)值
for (int j = 0; j < chessValue.length; j++) {
for (int i = 0; i < chessValue.length; i++) {
System.out.print(chessValue[i][j] + " ");
}
System.out.println();
}
// 電腦下棋
// 篩選出chessValue最大值的交點(diǎn)坐標(biāo), 該坐標(biāo)電腦下棋
for (int j = 0; j < chessValue.length; j++) {
for (int i = 0; i < chessValue.length; i++) {
if (chessValue[0][0] < chessValue[i][j]) {
chessValue[0][0] = chessValue[i][j];
t = i;
r = j;
}
}
}
count--;
chesses[t][r] = -1;
gr.drawImage(bai.getImage(), X0 + SIZE * t - CHESSSIZE / 2,
Y0 + SIZE * r - CHESSSIZE / 2, CHESSSIZE, CHESSSIZE, null);
cl = 1;
setX[index] = r;// 將下的棋子的橫坐標(biāo)存入setX[]
setY[index] = t;// 將下的棋子的縱坐標(biāo)存入setY[]
index++;// 存入一個(gè)坐標(biāo),一維數(shù)組角標(biāo)加1
checkRow(t, r);//判斷是否勝利
zz = 1;//
ww = 1;
// 清空value
for (int i = 0; i < chessValue.length; i++) {
for (int j = 0; j < chessValue.length; j++) {
chessValue[i][j] = 0;
}
}
}
}
}
}
}
}
}
// 判斷勝利的條件
public int checkRow(int x, int y) {
int count1 = 0, count2 = 0, count3 = 0, count4 = 0;// 定義4個(gè)棋子計(jì)數(shù)器,分別計(jì)數(shù)水平,豎直、斜向右下、斜向左下
for (int i = x + 1; i < chesses.length; i++) {
if (chesses[i][y] == chesses[x][y]) {
count1++;
} else
break;
}
for (int i = x; i >= 0; i--) {
if (chesses[i][y] == chesses[x][y]) {
count1++;
} else
break;
}
for (int j = y + 1; j < chesses.length; j++) {
if (chesses[x][j] == chesses[x][y]) {
count2++;
} else
break;
}
for (int j = y; j >= 0; j--) {
if (chesses[x][y] == chesses[x][j]) {
count2++;
} else
break;
}
for (int i = x + 1, j = y + 1; i < chesses.length && j < chesses.length; i++, j++) {
if (chesses[i][j] == chesses[x][y]) {
count3++;
} else
break;
}
for (int i = x, j = y; i >= 0 && j >= 0; i--, j--) {
if (chesses[i][j] == chesses[x][y]) {
count3++;
} else
break;
}
for (int i = x, j = y; i < chesses.length && j >= 0; i++, j--) {
if (chesses[i][j] == chesses[x][y]) {
count4++;
} else
break;
}
for (int i = x - 1, j = y + 1; i >= 0 && j < chesses.length; i--, j++) {
if (chesses[i][j] == chesses[x][y]) {
count4++;
} else
break;
}
if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5) {
count = 0;
if (cl == 0) {
JOptionPane.showMessageDialog(null, "黑棋贏!");
for (int i = 0; i < chesses.length; i++) {
for (int j = 0; j < chesses.length; j++) {
chesses[i][j] = 0;
}
}
fc.repaint();
}
if (cl == 1) {
JOptionPane.showMessageDialog(null, "白棋贏!");
for (int i = 0; i < chesses.length; i++) {
for (int j = 0; j < chesses.length; j++) {
chesses[i][j] = 0;
}
}
fc.repaint();
}
}
return count;
}
public void actionPerformed(ActionEvent e) {
name = e.getActionCommand();
if ("重新開始".equals(name)) {
count = 0;
z = 0;
w = 0;
for (int i = 0; i < chesses.length; i++) {
for (int j = 0; j < chesses.length; j++) {
chesses[i][j] = 0;
}
}
fc.repaint();
}
if ("白棋先下".equals(name)) {
if (z == 0) {
count = 1;
z = 1;
}
}
if ("黑棋先下".equals(name)) {
if (w == 0) {
count = 0;
w = 1;
}
}
if ("悔棋".equals(name)) {
this.huiqi();
}
if ("人機(jī)對(duì)戰(zhàn)".equals(name)) {
if(w==0){
AI = 1;
ww=1;
}
}
if ("人人對(duì)戰(zhàn)".equals(name)) {
if(z==0){
AI = 0;
}
}
}
public void huiqi() {
if (index >= 0) {
index--;
if (index < 0) {
index = 0;
}
x = setX[index];
y = setY[index];
if (chesses[x][y] == 1) {
chesses[x][y] = 0;
count = 0;
}
if (chesses[x][y] == -1) {
chesses[x][y] = 0;
count = 1;
}
if(chesses[t][r]==-1){
chesses[t][r]=0;
count=1;
}
fc.repaint();
}
}
public void AI() {
for (int i = 0; i < chesses.length; i++) {
for (int j = 0; j < chesses.length; j++) {
if (chesses[i][j] == 0) {// 判斷當(dāng)前位置是否有棋子
// 定義兩個(gè)變量分別保存棋局,顏色
String code = "";
int color = 0;
// 向右
for (int k = i + 1; k < chesses.length; k++) {
if (chesses[k][j] == 0) {
break;
} else {
if (color == 0) {// 右邊第一顆棋子
color = chesses[k][j];// 保存顏色
code += chesses[k][j];// 保存棋局
} else if (chesses[k][j] == color) {// 右邊第二,第三同顏色棋子
code += chesses[k][j];// 保存棋局
} else { // 右邊不同顏色
code += chesses[k][j];
break;
}
}
}
// 根據(jù)code取出hm對(duì)應(yīng)的權(quán)值
Integer value = hm.get(code);
if (value != null) {
chessValue[i][j] += value;
}
// 向左方向
code = "";
color = 0;
for (int k = i - 1; k >= 0; k--) {
if (chesses[k][j] == 0) {
break;
} else {
if (color == 0) {// 右邊第一顆棋子
color = chesses[k][j];// 保存顏色
code += chesses[k][j];// 保存棋局
} else if (chesses[k][j] == color) {// 右邊第二,第三同顏色棋子
code += chesses[k][j];// 保存棋局
} else { // 右邊不同顏色
code += chesses[k][j];
break;
}
}
}
// 根據(jù)code取出hm對(duì)應(yīng)的權(quán)值
Integer value2 = hm.get(code);
if (value2 != null) {
chessValue[i][j] += value2;
}
// 向上方向
code = "";
color = 0;
for (int k = j - 1; k >= 0; k--) {
if (chesses[i][k] == 0) {
break;
} else {
if (color == 0) {// 右邊第一顆棋子
color = chesses[i][k];// 保存顏色
code += chesses[i][k];// 保存棋局
} else if (chesses[i][k] == color) {// 右邊第二,第三同顏色棋子
code += chesses[i][k];// 保存棋局
} else { // 右邊不同顏色
code += chesses[i][k];
break;
}
}
}
// 根據(jù)code取出hm對(duì)應(yīng)的權(quán)值
Integer value3 = hm.get(code);
if (value3 != null) {
chessValue[i][j] += value3;
}
// 向下方向
code = "";
color = 0;
for (int k = j + 1; k < chesses.length; k++) {
if (chesses[i][k] == 0) {
break;
} else {
if (color == 0) {// 右邊第一顆棋子
color = chesses[i][k];// 保存顏色
code += chesses[i][k];// 保存棋局
} else if (chesses[i][k] == color) {// 右邊第二,第三同顏色棋子
code += chesses[i][k];// 保存棋局
} else { // 右邊不同顏色
code += chesses[i][k];
break;
}
}
}
// 根據(jù)code取出hm對(duì)應(yīng)的權(quán)值
Integer value4 = hm.get(code);
if (value4 != null) {
chessValue[i][j] += value4;
}
// 右上方向
code = "";
color = 0;
for (int k = j + 1, l = i - 1; l >= 0 && k < chesses.length; l--, k++) {
if (chesses[l][k] == 0) {
break;
} else {
if (color == 0) {// 右邊第一顆棋子
color = chesses[l][k];// 保存顏色
code += chesses[l][k];// 保存棋局
} else if (chesses[l][k] == color) {// 右邊第二,第三同顏色棋子
code += chesses[l][k];// 保存棋局
} else { // 右邊不同顏色
code += chesses[l][k];
break;
}
}
}
// 根據(jù)code取出hm對(duì)應(yīng)的權(quán)值
Integer value6 = hm.get(code);
if (value6 != null) {
chessValue[i][j] += value6;
}
// 左下方向
code = "";
color = 0;
for (int k = i + 1, l = j - 1; l >= 0 && k < chesses.length; k++, l--) {
if (chesses[k][l] == 0) {
break;
} else {
if (color == 0) {// 右邊第一顆棋子
color = chesses[k][l];// 保存顏色
code += chesses[k][l];// 保存棋局
} else if (chesses[k][l] == color) {// 右邊第二,第三同顏色棋子
code += chesses[k][l];// 保存棋局
} else { // 右邊不同顏色
code += chesses[k][l];
break;
}
}
}
// 根據(jù)code取出hm對(duì)應(yīng)的權(quán)值
Integer value7 = hm.get(code);
if (value7 != null) {
chessValue[i][j] += value7;
}
// 右下方向
code = "";
color = 0;
for (int k = i - 1, l = j - 1; l >= 0 && k >= 0; l--, k--) {
if (chesses[k][l] == 0) {
break;
} else {
if (color == 0) {// 右邊第一顆棋子
color = chesses[k][l];// 保存顏色
code += chesses[k][l];// 保存棋局
} else if (chesses[k][l] == color) {// 右邊第二,第三同顏色棋子
code += chesses[k][l];// 保存棋局
} else { // 右邊不同顏色
code += chesses[k][l];
break;
}
}
}
// 根據(jù)code取出hm對(duì)應(yīng)的權(quán)值
Integer value8 = hm.get(code);
if (value8 != null) {
chessValue[i][j] += value8;
}
// 左上方向
code = "";
color = 0;
for (int k = i + 1, l = j + 1; k < chesses.length && l < chesses.length; l++, k++) {
if (chesses[k][l] == 0) {
break;
} else {
if (color == 0) {// 右邊第一顆棋子
color = chesses[k][l];// 保存顏色
code += chesses[k][l];// 保存棋局
} else if (chesses[k][l] == color) {// 右邊第二,第三同顏色棋子
code += chesses[k][l];// 保存棋局
} else { // 右邊不同顏色
code += chesses[k][l];
break;
}
}
}
// 根據(jù)code取出hm對(duì)應(yīng)的權(quán)值
Integer value5 = hm.get(code);
if (value5 != null) {
chessValue[i][j] += value5;
}
}
}
}
}
}
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
Java關(guān)鍵字final、static使用總結(jié)
final方法不能被子類的方法覆蓋,但可以被繼承。用static修飾的代碼塊表示靜態(tài)代碼塊,當(dāng)Java虛擬機(jī)(JVM)加載類時(shí),就會(huì)執(zhí)行該代碼塊,下面通過本文給大家分享Java關(guān)鍵字final、static使用總結(jié),感興趣的朋友一起看看吧2017-07-07
java 實(shí)現(xiàn)字節(jié)流和字節(jié)緩沖流讀寫文件時(shí)間對(duì)比
這篇文章主要介紹了java 實(shí)現(xiàn)字節(jié)流和字節(jié)緩沖流讀寫文件時(shí)間對(duì)比,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01
springboot?全局異常處理和統(tǒng)一響應(yīng)對(duì)象的處理方式
這篇文章主要介紹了springboot?全局異常處理和統(tǒng)一響應(yīng)對(duì)象,主要包括SpringBoot 默認(rèn)的異常處理機(jī)制和SpringBoot 全局異常處理,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
IntelliJ IDEA 2020 安裝和常用配置(推薦)
這篇文章主要介紹了IntelliJ IDEA 2020 安裝和常用配置(推薦),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
SpringBoot集成Solr實(shí)現(xiàn)全文檢索功能
solr是一個(gè)現(xiàn)成的全文檢索引擎系統(tǒng), 放入tomcat下可以獨(dú)立運(yùn)行, 對(duì)外通過http協(xié)議提供全文檢索服務(wù),這篇文章給大家介紹了SpringBoot集成Solr實(shí)現(xiàn)全文檢索功能,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-03-03
SpringMVC4+MyBatis+SQL Server2014實(shí)現(xiàn)數(shù)據(jù)庫讀寫分離
這篇文章主要介紹了SpringMVC4+MyBatis+SQL Server2014實(shí)現(xiàn)讀寫分離,需要的朋友可以參考下2017-04-04
spring boot使用@Async異步注解的實(shí)現(xiàn)原理+源碼
通常我們都是采用多線程的方式來實(shí)現(xiàn)上述業(yè)務(wù)功能,但spring 提供更優(yōu)雅的方式來實(shí)現(xiàn)上述功能,就是@Async 異步注解,在方法上添加@Async,spring就會(huì)借助AOP,異步執(zhí)行方法,接下來通過本文給大家介紹spring boot異步注解的相關(guān)知識(shí),一起看看吧2021-06-06

