AI算法實(shí)現(xiàn)五子棋(java)
本文實(shí)例為大家分享了AI算法實(shí)現(xiàn)五子棋的具體代碼,供大家參考,具體內(nèi)容如下
首先,實(shí)現(xiàn)一個(gè)五子棋要有一個(gè)棋盤,然后在這個(gè)棋盤上我們?cè)賮懋嫵鰣D畫,五子棋棋盤有固定的行數(shù)和列數(shù),再加上界面的大小和菜單欄,這些數(shù)據(jù)可能很多個(gè)類都需要用到,我們可以先考慮自己寫一個(gè)接口用來存儲(chǔ)這些數(shù)據(jù):

public interface Config {
public static final int SIZE=703;
//面板大小
public static final int X0=SIZE/19*2-8;
public static final int Y0=X0-15;
//棋盤網(wǎng)格起始點(diǎn)
public static final int WID=SIZE/19;
//行寬
public static final int LINE=15;
//行數(shù)
public static final int CHESS=WID;
//五子棋棋子大小
}
這個(gè)時(shí)候我們來考慮寫一個(gè)五子棋界面,除了常用的界面寫法之外,考慮到五子棋的悔棋和重新開始,我們需要重寫paint方法,在需要的時(shí)候調(diào)用來達(dá)到更新棋盤的作用。
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class Fivebord extends JPanel implements Config{
private static final long serialVersionUID = 1L;
private int point[][]=new int [SIZE][SIZE];
public static void main(String[] args) {
Fivebord fb = new Fivebord();
fb.showFivebord();
}
public void showFivebord() {
//一下是關(guān)于界面的常規(guī)設(shè)置
javax.swing.JFrame jf = new javax.swing.JFrame();
jf.setTitle("FIVEBORD");
jf.setSize(SIZE+100, SIZE);
jf.setDefaultCloseOperation(3);
jf.setLocationRelativeTo(null);
jf.setLayout(new BorderLayout());
JPanel jp1=new JPanel();
jp1.setBackground(Color.ORANGE);
jp1.setPreferredSize(new Dimension(100, SIZE));
jf.add(jp1,BorderLayout.EAST);
javax.swing.JButton jbu1 = new javax.swing.JButton("悔棋");
jp1.add(jbu1);
javax.swing.JButton jbu2 = new javax.swing.JButton("人機(jī)");
jp1.add(jbu2);
javax.swing.JButton jbu3 = new javax.swing.JButton("人人");
jp1.add(jbu3);
this.setBackground(Color.YELLOW);
jf.add(this,BorderLayout.CENTER);
jf.setVisible(true);
//以下給界面添加監(jiān)聽器,包括畫板和按鈕
DrawMouse mouse=new DrawMouse(this);
jbu1.addActionListener(mouse);
jbu2.addActionListener(mouse);
jbu3.addActionListener(mouse);
this.addMouseListener(mouse);
//監(jiān)聽器中需要考慮當(dāng)前棋盤上的棋子和位置
mouse.setpoint(point);
}
public void paint(Graphics g) {
super.paint(g);
//super.paint
//由于paint函數(shù)是界面自帶的函數(shù)且在某些時(shí)候會(huì)自動(dòng)調(diào)用
//super.paint(g)表示屏蔽父類的函數(shù)內(nèi)容,換做自己接下來改寫的內(nèi)容
Graphics2D gr = (Graphics2D)g;
gr.setStroke(new BasicStroke(1));
//2D畫筆變粗度為1
for(int i=X0;i<=X0+LINE*WID;i+=WID){
for(int j=Y0;j<=Y0+LINE*WID;j+=WID){
g.drawLine(X0, j, X0+LINE*WID, j);
g.drawLine(i, Y0, i,Y0+LINE*WID);
}
}
//畫內(nèi)部16格
gr.setStroke(new BasicStroke(2));
//畫筆粗度變?yōu)?
g.drawLine(X0-WID, Y0-WID, X0-WID, Y0+(LINE+1)*WID);
g.drawLine(X0-WID, Y0-WID, X0+(LINE+1)*WID, Y0-WID);
g.drawLine(X0+(LINE+1)*WID, Y0-WID, X0+(LINE+1)*WID, Y0+(LINE+1)*WID);
g.drawLine(X0-WID, Y0+(LINE+1)*WID, X0+(LINE+1)*WID, Y0+(LINE+1)*WID);
//畫四周較粗的邊框(美觀起見,沒有實(shí)際意義)
for(int i=X0;i<=X0+(WID*(LINE+1));i+=WID){
for(int j=Y0;j<=Y0+(LINE+1)*WID;j+=WID){
if(point[i][j]==1){
//畫黑棋
g.setColor(Color.BLACK);
g.fillOval(i-WID/2, j-WID/2, WID, WID);
}
else if(point[i][j]==2){
//畫白棋
g.setColor(Color.WHITE);
g.fillOval(i-WID/2, j-WID/2, WID, WID);
}
}
}
//根據(jù)point的內(nèi)容畫出相應(yīng)的點(diǎn)(即棋子)
}
}
最最重要的就是監(jiān)聽器部分了,除了具有相應(yīng)的監(jiān)聽功能,還要在每次人下棋之后智能判斷出機(jī)器所需要下的位置,于此同時(shí),每下一個(gè)棋子,都要判斷是否已經(jīng)有五子連成線進(jìn)而提示輸贏。
import java.awt.Color;
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.JOptionPane;
public class DrawMouse extends MouseAdapter implements Config,ActionListener{
//添加動(dòng)作監(jiān)聽器(監(jiān)聽按鈕)和鼠標(biāo)監(jiān)聽器(鼠標(biāo)所點(diǎn)位置畫棋子)
private Graphics g;
private int x,y,CO=1,index=0;
private int point[][];
private int pointweight[][]=new int [X0+(LINE+1)*WID][Y0+(LINE+1)*WID];
private int orderx[]=new int [X0+(LINE+1)*WID],ordery[]=new int [Y0+(LINE+1)*WID];
private Fivebord fb;
private int pc=0;
public HashMap <String,Integer> hm = new HashMap <String,Integer>();
//哈希表用來存放不同棋子布局下的不同權(quán)值
DrawMouse(Fivebord fb) {
this.g = fb.getGraphics();
this.fb=fb;
sethashmap();
}
//傳棋子數(shù)組
public void setpoint(int point[][]){
this.point=point;
}
public void sethashmap(){
hm.put("1", 1);
//某一方向線上只有一個(gè)黑棋
hm.put("12", 5);
//某一方向線上緊接著一個(gè)黑棋有一個(gè)白棋
hm.put("11", 10);
hm.put("112", 15);
//某一方向線上緊接著兩個(gè)相鄰的黑棋后有一個(gè)白棋(以此類推)
hm.put("111", 100);
hm.put("1112", 105);
hm.put("1111", 1000);
hm.put("2", 1);
hm.put("21", 5);
hm.put("22", 10);
hm.put("221", 15);
hm.put("222", 100);
hm.put("2221", 105);
hm.put("2222", 1000);
}
public void actionPerformed(ActionEvent e){
//悔棋操作,將棋子數(shù)目減一,然后重繪界面即可
if("悔棋".equals(e.getActionCommand())&&index>0){
System.out.println("悔棋");
index--;
point[orderx[index]][ordery[index]]=0;
fb.paint(g);
}
//人機(jī)模式一旦點(diǎn)擊,界面所有棋子清零,開始人機(jī)對(duì)戰(zhàn)(pc=1)
if("人機(jī)".equals(e.getActionCommand())){
System.out.println("人機(jī)");
pc=1;
index=0;
for(int i=X0;i<=X0+WID*LINE;i+=WID){
for(int j=Y0;j<=Y0+WID*LINE;j+=WID){
point[i][j]=0;
}
}
fb.paint(g);
}
//人人對(duì)戰(zhàn),也是點(diǎn)擊按鈕棋子清零,開始人人對(duì)戰(zhàn)(pc=0)
if("人人".equals(e.getActionCommand())){
System.out.println("人機(jī)");
pc=0;
index=0;
for(int i=X0;i<=X0+WID*LINE;i+=WID){
for(int j=Y0;j<=Y0+WID*LINE;j+=WID){
point[i][j]=0;
}
}
fb.paint(g);
}
}
public void mouseClicked(MouseEvent e) {
x=e.getX();
y=e.getY();
//得到點(diǎn)擊的點(diǎn)
if((x-X0)%WID>=WID/2){
x=x-(x-X0)%WID+WID;
}
else{
x=x-(x-X0)%WID;
}
if((y-Y0)%WID>=WID/2){
y=y-(y-Y0)%WID+WID;
}
else{
y=y-(y-Y0)%WID;
}
//對(duì)點(diǎn)的位置進(jìn)行修正(保證每次點(diǎn)擊都正好下在網(wǎng)格交匯處)
if(point[x][y]==0&&x>=X0&&x<=X0+WID*LINE&&y>=Y0&&y<=Y0+WID*LINE){
//人人對(duì)戰(zhàn):直接用鼠標(biāo)檢測,依次變換顏色黑或白
if(pc==0){
if(g.getColor()==Color.black){
g.setColor(Color.WHITE);
CO=2;
}
else{
g.setColor(Color.BLACK);
CO=1;
}
}
//人機(jī)對(duì)戰(zhàn),每次人下過棋子之后,計(jì)算機(jī)根據(jù)現(xiàn)有棋盤布局對(duì)棋局分析和總和并判斷機(jī)器需要下的位置
else if(pc==1){
g.setColor(Color.BLACK);
CO=1;
}
g.fillOval(x-WID/2, y-WID/2, WID, WID);
point[x][y]=CO;
System.out.println(index+ " "+ x+" "+y);
orderx[index]=x;
ordery[index]=y;
index++;
if(exam()==0){
//自己敲代碼過程中的驗(yàn)證、、、、、、可以不用在意這類輸出。
System.out.println("hahahahhhaahhahah");
if(pc==1){
System.out.println("HEHEHEHEHEHEHEHEHEHEHE");
g.setColor(Color.WHITE);
CO=2;
AI();
exam();
}
}
}
}
//檢測是否有一方獲勝,跳出提示框提示某一方獲勝
public int exam(){
int w=0;
for(int i=X0-WID;i<=X0+WID*(LINE+1);i+=WID){
for(int j=Y0-WID;j<=Y0+WID*(LINE+1);j+=WID){
if(point[i][j]!=0){
int exam1=0,exam2=0,exam3=0,exam4=0;
//水平、豎直、左斜、右斜四個(gè)方向上同色棋子相連最多的個(gè)數(shù)
for(int t=WID;t<5*WID;t+=WID){
if(i+t<=X0+WID*(LINE+1)&&point[i+t][j]==point[i][j]){
exam1++;
}
if(j+t<=Y0+WID*(LINE+1)&&point[i][j+t]==point[i][j]){
exam2++;
}
if(i+t<=X0+WID*(LINE+1)&&j+t<=Y0+WID*(LINE+1)&&point[i+t][j+t]==point[i][j]){
exam3++;
}
if(i+t<=X0+WID*(LINE+1)&&j>=t&&point[i+t][j-t]==point[i][j]){
exam4++;
}
}
System.out.println(exam1+" "+exam2+" " +exam3+" "+exam4);
if(exam1==4||exam2==4||exam3==4||exam4==4){//某一方向上同色5子相連,一方獲勝
if(point[i][j]==1){
w=1;
//彈出提示框
JOptionPane.showMessageDialog(null, "黑子勝");
}
else{
w=2;
JOptionPane.showMessageDialog(null, "白子勝");
}
i=X0+WID*(LINE+1)+1;
break;
}
}
}
}
return w;
}
//AI算法
//分別向左、香油、左下、、、、、等8個(gè)方向檢測棋子布局情況并累加在該點(diǎn)的權(quán)值上
//再找出圖片上沒有棋子并且權(quán)值最大的點(diǎn)下棋子
//記得每次下棋將各個(gè)空位置的權(quán)值歸0,以便下一次計(jì)算權(quán)值累加
public void AI(){
for(int i=X0;i<X0+WID*(LINE+1);i+=WID){
for(int j=Y0;j<Y0+WID*(LINE+1);j+=WID){
if(point[i][j]==0){
//像右尋找
//System.out.print("pointweight["+(i-X0)/WID+"]["+(j-Y0)/WID+"]:");
int color=0;
String code="";
for(int k=i+WID;k<=X0+WID*LINE;k+=WID){
if(point[k][j]!=0){
if(color==0){
color=point[k][j];
code+=point[k][j];
}
else{
if(point[k][j]==color){
code+=point[k][j];
}
else{
code+=point[k][j];
break;
}
}
}
else{
break;
}
}
Integer value=hm.get(code);
if(value != null){
pointweight[i][j] += value;
}
//向下尋找
// System.out.print(pointweight[i][j]+" ");
code="";
color=0;
for(int k=j+WID;k<=X0+WID*LINE;k+=WID){
if(point[i][k]!=0){
if(color==0){
color=point[i][k];
code+=point[i][k];
}
else{
if(point[i][k]==color){
code+=point[i][k];
}
else{
code+=point[i][k];
break;
}
}
}
else{
break;
}
}
value=hm.get(code);
if(value != null){
pointweight[i][j] += value;
}
//向左
// System.out.print(pointweight[i][j]+" ");
code="";
color=0;
for(int k=i-WID;k>=X0;k-=WID){
if(point[k][j]!=0){
if(color==0){
color=point[k][j];
code+=point[k][j];
}
else{
if(point[k][j]==color){
code+=point[k][j];
}
else{
code+=point[k][j];
break;
}
}
}
else{
break;
}
}
value=hm.get(code);
if(value != null){
pointweight[i][j] += value;
}
//向上
// System.out.print(pointweight[i][j]+" ");
code="";
color=0;
for(int k=j-WID;k>=Y0;k-=WID){
if(point[i][k]!=0){
if(color==0){
color=point[i][k];
code+=point[i][k];
}
else{
if(point[i][k]==color){
code+=point[i][k];
}
else{
code+=point[i][k];
break;
}
}
}
else{
break;
}
}
value=hm.get(code);
if(value != null){
pointweight[i][j] += value;
}
//向右上尋找
// System.out.print(pointweight[i][j]+" ");
code="";
color=0;
for(int k=i+WID,w=j+WID;k<=X0+WID*LINE&&w<=Y0+WID*LINE;k+=WID,w+=WID){
if(point[k][w]!=0){
if(color==0){
color=point[k][w];
code+=point[k][w];
}
else{
if(point[k][w]==color){
code+=point[k][w];
}
else{
code+=point[k][w];
break;
}
}
}
else{
break;
}
}
value=hm.get(code);
if(value != null){
pointweight[i][j] += value;
}
// System.out.print(pointweight[i][j]+" ");
code="";
color=0;
for(int k=i-WID,w=j-WID;k>=X0&&w>=Y0;k-=WID,w-=WID){
if(point[k][w]!=0){
if(color==0){
color=point[k][w];
code+=point[k][w];
}
else{
if(point[k][w]==color){
code+=point[k][w];
}
else{
code+=point[k][w];
break;
}
}
}
else{
break;
}
}
value=hm.get(code);
if(value != null){
pointweight[i][j] += value;
}
// System.out.print(pointweight[i][j]+" ");
code="";
color=0;
for(int k=i+WID,w=j-WID;k<=X0+LINE*WID&&w>=Y0;k+=WID,w-=WID){
if(point[k][w]!=0){
if(color==0){
color=point[k][w];
code+=point[k][w];
}
else{
if(point[k][w]==color){
code+=point[k][w];
}
else{
code+=point[k][w];
break;
}
}
}
else{
break;
}
}
value=hm.get(code);
if(value != null){
pointweight[i][j] += value;
}
// System.out.print(pointweight[i][j]+" ");
code="";
color=0;
for(int k=i-WID,w=j+WID;k>=X0&&w<=Y0+LINE*WID;k-=WID,w+=WID){
if(point[k][w]!=0){
if(color==0){
color=point[k][w];
code+=point[k][w];
}
else{
if(point[k][w]==color){
code+=point[k][w];
}
else{
code+=point[k][w];
break;
}
}
}
else{
break;
}
}
value=hm.get(code);
if(value != null){
pointweight[i][j] += value;
}
// System.out.println(pointweight[i][j]);
}
}
}
//尋找最大權(quán)值的點(diǎn)并畫棋子
int maxx=X0,maxy=Y0;
for(int i=X0;i<=X0+WID*LINE;i+=WID){
for(int j=Y0;j<=Y0+WID*LINE;j+=WID){
System.out.print(pointweight[i][j]+" ");
if(pointweight[i][j]>pointweight[maxx][maxy]){
maxx=i;
maxy=j;
}
}
System.out.println();
}
g.fillOval(maxx-WID/2, maxy-WID/2, WID, WID);
point[maxx][maxy]=CO;
System.out.println(index+ " "+ maxx+" "+maxy);
orderx[index]=maxx;
ordery[index]=maxy;
index++;
//全部權(quán)值歸零方便下次使用
for(int i=X0;i<=X0+WID*LINE;i+=WID){
for(int j=Y0;j<=Y0+WID*LINE;j+=WID){
pointweight[i][j]=0;
}
}
}
}
大概就是這個(gè)樣子了,權(quán)值那里設(shè)置的還是需要調(diào)整一下。運(yùn)行結(jié)果截圖如下:

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java C++實(shí)現(xiàn)相同MD5加密算法的方式
這篇文章主要介紹了Java與C++實(shí)現(xiàn)相同MD5加密算法的方法,需要的朋友可以參考下面文章內(nèi)容2021-09-09
restTemplate發(fā)送get與post請(qǐng)求并且?guī)?shù)問題
這篇文章主要介紹了restTemplate發(fā)送get與post請(qǐng)求并且?guī)?shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Java超詳細(xì)教你寫一個(gè)學(xué)籍管理系統(tǒng)案例
這篇文章主要介紹了怎么用Java來寫一個(gè)學(xué)籍管理系統(tǒng),學(xué)籍管理主要涉及到學(xué)生信息的增刪查改,本篇將詳細(xì)的實(shí)現(xiàn),感興趣的朋友跟隨文章往下看看吧2022-03-03
Java中l(wèi)ogback?自動(dòng)刷新不生效的問題解決
本文主要介紹了Java中l(wèi)ogback?自動(dòng)刷新不生效的問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
mybatis多層嵌套resultMap及返回自定義參數(shù)詳解
這篇文章主要介紹了mybatis多層嵌套resultMap及返回自定義參數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12

