AI算法實現(xiàn)五子棋(java)
本文實例為大家分享了AI算法實現(xiàn)五子棋的具體代碼,供大家參考,具體內(nèi)容如下
首先,實現(xiàn)一個五子棋要有一個棋盤,然后在這個棋盤上我們再來畫出圖畫,五子棋棋盤有固定的行數(shù)和列數(shù),再加上界面的大小和菜單欄,這些數(shù)據(jù)可能很多個類都需要用到,我們可以先考慮自己寫一個接口用來存儲這些數(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)格起始點
public static final int WID=SIZE/19;
//行寬
public static final int LINE=15;
//行數(shù)
public static final int CHESS=WID;
//五子棋棋子大小
}
這個時候我們來考慮寫一個五子棋界面,除了常用的界面寫法之外,考慮到五子棋的悔棋和重新開始,我們需要重寫paint方法,在需要的時候調(diào)用來達到更新棋盤的作用。
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ī)設置
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);
//以下給界面添加監(jiān)聽器,包括畫板和按鈕
DrawMouse mouse=new DrawMouse(this);
jbu1.addActionListener(mouse);
jbu2.addActionListener(mouse);
jbu3.addActionListener(mouse);
this.addMouseListener(mouse);
//監(jiān)聽器中需要考慮當前棋盤上的棋子和位置
mouse.setpoint(point);
}
public void paint(Graphics g) {
super.paint(g);
//super.paint
//由于paint函數(shù)是界面自帶的函數(shù)且在某些時候會自動調(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);
//畫四周較粗的邊框(美觀起見,沒有實際意義)
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)容畫出相應的點(即棋子)
}
}
最最重要的就是監(jiān)聽器部分了,除了具有相應的監(jiān)聽功能,還要在每次人下棋之后智能判斷出機器所需要下的位置,于此同時,每下一個棋子,都要判斷是否已經(jīng)有五子連成線進而提示輸贏。
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{
//添加動作監(jiān)聽器(監(jiān)聽按鈕)和鼠標監(jiā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>();
//哈希表用來存放不同棋子布局下的不同權值
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);
//某一方向線上只有一個黑棋
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){
//悔棋操作,將棋子數(shù)目減一,然后重繪界面即可
if("悔棋".equals(e.getActionCommand())&&index>0){
System.out.println("悔棋");
index--;
point[orderx[index]][ordery[index]]=0;
fb.paint(g);
}
//人機模式一旦點擊,界面所有棋子清零,開始人機對戰(zhàn)(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);
}
//人人對戰(zhàn),也是點擊按鈕棋子清零,開始人人對戰(zhàn)(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;
}
//對點的位置進行修正(保證每次點擊都正好下在網(wǎng)格交匯處)
if(point[x][y]==0&&x>=X0&&x<=X0+WID*LINE&&y>=Y0&&y<=Y0+WID*LINE){
//人人對戰(zhàn):直接用鼠標檢測,依次變換顏色黑或白
if(pc==0){
if(g.getColor()==Color.black){
g.setColor(Color.WHITE);
CO=2;
}
else{
g.setColor(Color.BLACK);
CO=1;
}
}
//人機對戰(zhàn),每次人下過棋子之后,計算機根據(jù)現(xiàn)有棋盤布局對棋局分析和總和并判斷機器需要下的位置
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;
//水平、豎直、左斜、右斜四個方向上同色棋子相連最多的個數(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個方向檢測棋子布局情況并累加在該點的權值上
//再找出圖片上沒有棋子并且權值最大的點下棋子
//記得每次下棋將各個空位置的權值歸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;
}
}
}
}
大概就是這個樣子了,權值那里設置的還是需要調(diào)整一下。運行結果截圖如下:

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
restTemplate發(fā)送get與post請求并且?guī)?shù)問題
這篇文章主要介紹了restTemplate發(fā)送get與post請求并且?guī)?shù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
Java中l(wèi)ogback?自動刷新不生效的問題解決
本文主要介紹了Java中l(wèi)ogback?自動刷新不生效的問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-05-05
mybatis多層嵌套resultMap及返回自定義參數(shù)詳解
這篇文章主要介紹了mybatis多層嵌套resultMap及返回自定義參數(shù)詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12

