您好,登錄后才能下訂單哦!
本文實例為大家分享了AI算法實現五子棋的具體代碼,供大家參考,具體內容如下
首先,實現一個五子棋要有一個棋盤,然后在這個棋盤上我們再來畫出圖畫,五子棋棋盤有固定的行數和列數,再加上界面的大小和菜單欄,這些數據可能很多個類都需要用到,我們可以先考慮自己寫一個接口用來存儲這些數據:
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; //棋盤網格起始點 public static final int WID=SIZE/19; //行寬 public static final int LINE=15; //行數 public static final int CHESS=WID; //五子棋棋子大小 }
這個時候我們來考慮寫一個五子棋界面,除了常用的界面寫法之外,考慮到五子棋的悔棋和重新開始,我們需要重寫paint方法,在需要的時候調用來達到更新棋盤的作用。
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() { //一下是關于界面的常規設置 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("人機"); 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); //以下給界面添加監聽器,包括畫板和按鈕 DrawMouse mouse=new DrawMouse(this); jbu1.addActionListener(mouse); jbu2.addActionListener(mouse); jbu3.addActionListener(mouse); this.addMouseListener(mouse); //監聽器中需要考慮當前棋盤上的棋子和位置 mouse.setpoint(point); } public void paint(Graphics g) { super.paint(g); //super.paint //由于paint函數是界面自帶的函數且在某些時候會自動調用 //super.paint(g)表示屏蔽父類的函數內容,換做自己接下來改寫的內容 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); } } //畫內部16格 gr.setStroke(new BasicStroke(2)); //畫筆粗度變為2 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); //畫四周較粗的邊框(美觀起見,沒有實際意義) 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); } } } //根據point的內容畫出相應的點(即棋子) } }
最最重要的就是監聽器部分了,除了具有相應的監聽功能,還要在每次人下棋之后智能判斷出機器所需要下的位置,于此同時,每下一個棋子,都要判斷是否已經有五子連成線進而提示輸贏。
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{ //添加動作監聽器(監聽按鈕)和鼠標監聽器(鼠標所點位置畫棋子) 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>(); //哈希表用來存放不同棋子布局下的不同權值 DrawMouse(Fivebord fb) { this.g = fb.getGraphics(); this.fb=fb; sethashmap(); } //傳棋子數組 public void setpoint(int point[][]){ this.point=point; } public void sethashmap(){ hm.put("1", 1); //某一方向線上只有一個黑棋 hm.put("12", 5); //某一方向線上緊接著一個黑棋有一個白棋 hm.put("11", 10); hm.put("112", 15); //某一方向線上緊接著兩個相鄰的黑棋后有一個白棋(以此類推) 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){ //悔棋操作,將棋子數目減一,然后重繪界面即可 if("悔棋".equals(e.getActionCommand())&&index>0){ System.out.println("悔棋"); index--; point[orderx[index]][ordery[index]]=0; fb.paint(g); } //人機模式一旦點擊,界面所有棋子清零,開始人機對戰(pc=1) if("人機".equals(e.getActionCommand())){ System.out.println("人機"); 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); } //人人對戰,也是點擊按鈕棋子清零,開始人人對戰(pc=0) if("人人".equals(e.getActionCommand())){ System.out.println("人機"); 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(); //得到點擊的點 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; } //對點的位置進行修正(保證每次點擊都正好下在網格交匯處) if(point[x][y]==0&&x>=X0&&x<=X0+WID*LINE&&y>=Y0&&y<=Y0+WID*LINE){ //人人對戰:直接用鼠標檢測,依次變換顏色黑或白 if(pc==0){ if(g.getColor()==Color.black){ g.setColor(Color.WHITE); CO=2; } else{ g.setColor(Color.BLACK); CO=1; } } //人機對戰,每次人下過棋子之后,計算機根據現有棋盤布局對棋局分析和總和并判斷機器需要下的位置 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){ //自己敲代碼過程中的驗證、、、、、、可以不用在意這類輸出。 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; //水平、豎直、左斜、右斜四個方向上同色棋子相連最多的個數 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個方向檢測棋子布局情況并累加在該點的權值上 //再找出圖片上沒有棋子并且權值最大的點下棋子 //記得每次下棋將各個空位置的權值歸0,以便下一次計算權值累加 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]); } } } //尋找最大權值的點并畫棋子 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++; //全部權值歸零方便下次使用 for(int i=X0;i<=X0+WID*LINE;i+=WID){ for(int j=Y0;j<=Y0+WID*LINE;j+=WID){ pointweight[i][j]=0; } } } }
大概就是這個樣子了,權值那里設置的還是需要調整一下。運行結果截圖如下:
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。