📄 gobang.java
字号:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
class Gobang extends JPanel
{
final static int succCount=5;//成功所需要连接的最少棋子数
private static int rows=10;
private static int cols=rows;
private static Chessman [][] c=new Chessman[rows][cols];//棋盘
private static Win w=null;//算法对象
private static JTextField text1=new JTextField(6),
text2=new JTextField(6),
text3=new JTextField(6);
Gobang()
{
setBackground(Color.white);
setLayout(new GridLayout(rows,cols));
for(int i=0;i<rows;i++)
for(int j=0;j<cols;j++)
{
c[i][j]=new Chessman(rows,cols);
add(c[i][j]);
}
w=new Win(c);//胜负算法
new Peeker();//监视器
}
public static void main(String [] args)
{
JFrame jf=new JFrame("DemoMe");
JPanel southPanel = new JPanel(),
northPanel = new JPanel();
southPanel.setLayout(new FlowLayout());
northPanel.setLayout(new FlowLayout());
northPanel.add(new JLabel("Gobang"));
southPanel.add(new JLabel("NullChess"));
southPanel.add(text1);
southPanel.add(new JLabel("isFull"));
southPanel.add(text2);
southPanel.add(new JLabel("GameOver"));
southPanel.add(text3);
jf.getContentPane().setLayout(new BorderLayout());
jf.getContentPane().add(new Gobang(),BorderLayout.CENTER);
jf.getContentPane().add(southPanel,BorderLayout.SOUTH);
jf.getContentPane().add(northPanel,BorderLayout.NORTH);
jf.setBackground(Color.white);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(500,540);
jf.setVisible(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
}
class Peeker extends Thread//监测状态
{
Peeker(){start();}
public void run()
{
while(true){
try{
sleep(500);
}catch(InterruptedException e){
System.out.println("error 1: sleep(200) in class Peeker");
}
text1.setText(Chessman.getNullChess()+"");
text2.setText(Chessman.isFull()+"");
text3.setText(w.GetGameOver()+"");
if(w.GetGameOver()!=-1)
{
for(int i=0;i<rows;i++)
for(int j=0;j<cols;j++)
c[i][j].removeMouseListener();
gameOver(w.GetGameOver());
}
}
}
}
private void gameOver(int state)
{
//todo
}
}
class Chessman extends JButton
{
private static int nullChess=0; //状态为空的棋子数
private static int totalChess=0; //棋子总数
private Color colorOfBoard=Color.ORANGE;//棋子颜色
static int getNullChess(){return nullChess;}
//棋子状态
public final static int NULL=0;//空
public final static int PLAYER=1; //我方占有
public final static int COMPUTER=2;//电脑占有
private int currStatus=NULL;//当前棋子状态
private static int i=0,j=0; //坐标排列计数器
private int x,y; //当前对象在二维对象数组中的坐标
private static int rows,cols;//所有Buton对象构成的矩阵行列数
private MyMouseAdapter mma=null;
Chessman(int r,int c)
{
rows=r;
cols=c;
x=i;
y=j;
if(++j==c)
{
i++;
j=0;
}
nullChess++;
totalChess++;
setBackground(colorOfBoard);//棋子背景色
setSize(10,10);
mma=new MyMouseAdapter();
addMouseListener(mma);
}
void removeMouseListener()
{
if(mma!=null)
removeMouseListener(mma);
}
private class MyMouseAdapter extends MouseAdapter
{
public void mouseReleased(MouseEvent e)
{
if(currStatus==NULL)
{
if(e.getButton()==e.BUTTON3)//鼠标右键
currStatus=COMPUTER;
if(e.getButton()==e.BUTTON1)//鼠标左键
currStatus=PLAYER;
nullChess--;
repaint();
Win.win1(Chessman.this);
}
else if(currStatus!=NULL&&e.getClickCount()==2)//双击使棋子状态为空
{
currStatus=NULL;
nullChess++;
repaint();
}
}
}
public void paintComponent(Graphics g)//重绘仅只是当前单个按钮
{
super.paintComponent(g);//重绘背景
g.setXORMode(Chessman.this.getBackground());
if(currStatus==NULL)
{
g.drawString(x+" "+y,15,25);//此对象的坐标
return; //重绘完背景即返回
}
if(currStatus==PLAYER)
g.setColor(Color.black);
if(currStatus==COMPUTER)
g.setColor(Color.white);
int x=getSize().width/10;
int y=getSize().height/10;
g.fillOval(x,y,9*x,9*y);
}
int getStatus()
{
return currStatus;//返回当前棋子状态
}
void setCurrStatus(int s)
{
if(s<0||s>2)
return;
if(s==NULL)
nullChess++;
else
nullChess--;
currStatus=s;
repaint();
Win.win1(this);
// Win.push(this);//使当前棋子在填充\判断胜负后在白方的步骤数组中进站以更新步骤数组
}
static boolean isFull()//棋盘是否被填满
{
return (nullChess==0&&totalChess!=0);
}
int getPX(){return x;}
int getPY(){return y;}
public String toString()
{
return "["+x+","+y+"]="+currStatus;
}
}
/*整个程序只能存在一个Win对象及其对应的一个AI对象*/
class Win//用于计算
{
private static int rows,cols; //棋盘大小
private static int winFlag=-1;//平局NULL,我方胜PLAYER,否则COMPUTER,-1则色么都不是
/*小心这里最好不要使用静态Chessman*/
private static Chessman chessman=null;//当前棋子对象
private static final int NULL=Chessman.NULL;
private static final int PLAYER=Chessman.PLAYER;
private static final int COMPUTER=Chessman.COMPUTER;
private static int nullChess=0;
private static Chessman [][] b=null;//棋盘对象
private static AI ai=null; //电脑行进对象
final int WARNNINGLEVEL=3;//指定的危险级别,当达到此级别时应作出相应的操作
Win(Chessman [][] b)
{
this.b=b;
rows=b.length;
cols=b[0].length;
ai=new AI();
}
/*
*棋子对象作参数
*判断胜负平局
*并使COMPUTER下棋
**/
static void win1(Chessman c)
{
chessman=c; //总是将当前调用win1()的对象的this传过来以更新本类中的chessman引用
int state=c.getStatus();
switch (state)//由state判断对当前棋子对象是色么动作
{
case NULL:
//若被取消的是白棋则ai.pop();
return;
case PLAYER:
if(win2(c)==true)
winFlag=PLAYER;
else if(!chessman.isFull())//PLAYER操作后未胜且棋盘不满则允许COMPUTER操作
ai.mode_2();//ai.mode_x()仅为电脑的行进提供操作
break;
case COMPUTER:
if(win2(c)==true)
winFlag=COMPUTER;
/* else if(!chessman.isFull())
ai.StackWhite.push(c);//白子进栈*/
break;
default:
{System.out.println("error 0");}
}
if(winFlag==-1&&chessman.isFull())
winFlag=NULL;//平局
}
private static boolean win2(Chessman c)
{
int x=c.getPX(),y=c.getPY();
int state=c.getStatus();
int count=0;
int i,j;
// System.out.println("*******************win2 start***************");
// System.out.println("(x,y)="+x+","+y);
// System.out.println("this.getStatus()="+c.getStatus());
for(i=x-1;i<=x+1;i++)
for(j=y-1;j<=y+1;j++)
{
// System.out.println("(i,j)="+i+","+j);
// System.out.println("b[i][j].getStatus()="+b[i][j].getStatus());
// try{
// System.in.read();
// }catch(IOException e){}
//(b[i][j]!=c)判断是否是同一个实列,而不仅是值相等
if(i>=0&&i<rows&&j>=0&&j<cols&&(b[i][j].getStatus()==state)&&(b[i][j]!=c))
{
// System.out.print("进入if(..)\t");
// System.out.println("b["+i+"]["+j+"]="+b[i][j].getStatus());
// try{
// System.in.read();
// }catch(IOException e){}
int dr=x-i,dc=y-j;
int m=i,n=j;
count=1;
while(m>=0&&m<rows&&n>=0&&n<cols&&(b[m][n].getStatus()==state))
{
// System.out.print("进入 1st while()\t");
// System.out.println("b["+m+"]["+n+"]="+b[m][n].getStatus());
// try{
// System.in.read();
// }catch(IOException e){}
m-=dr;n-=dc;
}
m+=dr;n+=dc;
while(m>=0&&m<rows&&n>=0&&n<cols&&(b[m][n].getStatus()==state))
{
// System.out.print("进入 2nd while()\t");
// System.out.println("b["+m+"]["+n+"]="+b[m][n].getStatus());
// System.out.println("count="+count);
// try{
// System.in.read();
// }catch(IOException e){}
if(count++>=Gobang.succCount)//进入这个while才开始计数
{
// System.out.println("return true;");
// System.out.println("****************win2 finished**************");
return true;
}
m+=dr;n+=dc;
}
}
}
// System.out.println("return false;");
// System.out.println("****************win2 finished**************");
return false;
}
private class AI//考虑COMPUER的行进
{
/***************************************第一种AI*****************************/
private Random rnd=new Random();
private Chessman [] s=new Chessman[2*rows+2*cols-4];//mode_1函数所使用的堆栈
private int top=-1;
//电脑在我方下完一个黑子后在离此黑子最近的一些状态为空的棋子上随机填充
void mode_1()
{
//只要棋盘中还存在空位就一定能找到以供COMPUTER填充
top=-1;
mode_1(1);//初始调用检测对象为离当前操作棋子的距离为1的8个棋子
}
//distance为离我方所下的这个棋子的距离范围(在这个范围内检测)
private void mode_1(int distance)
{
for(int i=chessman.getPX()-distance;i<=chessman.getPX()+distance;i++)
for(int j=chessman.getPY()-distance;j<=chessman.getPY()+distance;j++)
if(i>=0&&i<rows&&j>=0&&j<cols&&b[i][j].getStatus()==NULL)
s[++top]=b[i][j];//数组中存储找到满足要求的位置
if(top==-1)//未找到任何一个满足要求的位置
mode_1(distance+1);//扩大距离范围继续找
else
{
/* System.out.println("************ In mode_1() ***************");
System.out.println("distance="+distance);
System.out.println("堆栈中的棋子:");
for(int i=0;i<=top;i++)
System.out.println("b["+s[i].getPX()+"]["+s[i].getPY()+"]="+s[i].getStatus());
System.out.println("************ End mode_1() ***************");
*/
//在所有找到离黑方当前所下棋子最近的空位中随机取其中一个使COMPUTER填充
s[rnd.nextInt(top+1)].setCurrStatus(COMPUTER);
}
}
/****************************************第二种AI**********************************/
//当前所检测到的黑子四条直线上的危险级别及电脑所准备填充的棋子坐标
//类中的每个元素都具有初始值则在new对象时会自动对他们赋为这些初始值
class warnning{
//当前方向上的危险级别
int warnningLevel=0;
//在这条直线上对对方最具危险的点(此点状态为空)
//(-1,-1)为没有找到
//当两个点的威胁级别相同时分别存入两个坐标,否则只将最大
//值存入(x1,y1),(x2,y2)为(-1,-1)
int x1=-1,y1=-1,x2=-1,y2=-1;
//标示是否两个坐标具有相同的最大值
boolean flag=false;
}
private warnning [] warnningBlack=null;
private void mode_2()
{
if(Chessman.getNullChess()==rows*cols-1)
mode_1();
else if(Chessman.getNullChess()==1)
mode_1();
else
{
//检测危险,若达到指定威胁级别则返回威胁最大的空白棋子
//否则返回null
Chessman space=checkWarnning();
if(space==null)
{
System.out.println("未达到危险级别"+WARNNINGLEVEL);
System.out.println("使用mode_1()填充");
//computerPlayChess();
mode_1();
}
else //现在space是威胁最大的空白棋子,将其填充
space.setCurrStatus(COMPUTER);
}
}
private Chessman checkWarnning()
{
warnningBlack=new warnning[4];//四个方向
//初始化warnningBlack数组
initWarnningArray(warnningBlack,chessman);
System.out.println("************* start checkWarnning() ***********");
//找出最大的危险方向及允许填充的空位
//(最高的level对应的Position)然后填充setCurrStatus(COMPUTER)
int max=warnningBlack[0].warnningLevel;
int k=0;
//此数组存储所有具有相同最大级别的warnning对象
warnning [] temp=new warnning[4];
int index=-1;
//找出一个最大级别的warnning对象
for(int i=0;i<warnningBlack.length;i++)
if(warnningBlack[i].warnningLevel>max)
{max=warnningBlack[i].warnningLevel;k=i;}
System.out.println("找到第一个最大warnning级别对象\n"
+"b["+warnningBlack[k].x1+"]["+warnningBlack[k].y1+"]");
System.out.println("maxWarnning="+max);
if(max>=WARNNINGLEVEL)
{
//将级别具有最大相同值的对象入temp[]
for(int i=0;i<warnningBlack.length;i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -