最近做了一个简单的五子棋游戏,其中涉及到界面的布局设计,以及简单的AI算法的应用。
我创建了五个类。
1、public class ChessJpanel extends JPanel implements Config:这个类中我主要写棋盘的设计以及画面的还原代码。
2、public interface Config:写了一个接口,其中主要是关于棋盘内棋子,网格等尺寸的参数的保存,一般也在此处修改参数。
3、public class DrawFrame:此类中我写界面的初始化设计,主函数也在其中。
4、public class DrawMouse implements ActionListener, MouseMotionListener, MouseListener, Config:这个类中我写了监听器的程序,以及AI算法,这个类也是包含内容最多的类了。用到了动作监听器、鼠标监听器,继承了参数接口。
5、public class Shape implements Config:此类用于设置棋子的位置颜色等参数,继承接口。
我们先贴出界面的部分代码:
public class DrawFrame {
public static void main(String[] args) {
DrawFrame frame = new DrawFrame();
frame.showUI();
}
public void showUI() {
// 创建窗体对象
javax.swing.JFrame jf = new javax.swing.JFrame();
ImageIcon img = new ImageIcon("E:\\workspace\\mayifan\\src\\com\\myf\\gobang1030\\timg.jpg");
JLabel jla = new JLabel(img);
jf.getLayeredPane().add(jla, new Integer(Integer.MIN_VALUE));
jla.setBounds(0, 0, 950, 640);
JPanel jp1 = (JPanel) jf.getContentPane();
jp1.setOpaque(false);
jf.setSize(950, 640);
//jf.getContentPane().setBackground(Color.ORANGE);//设置背景色
jf.setTitle("五子棋");
jf.setDefaultCloseOperation(3);
// 设置居中显示
jf.setLocationRelativeTo(null);
DrawMouse mouse = new DrawMouse();
JButton jb1=new JButton("新游戏");
jf.add(jb1);
jb1.setBounds(675, 185, 100,40);
jb1.addActionListener(mouse);
JButton jb2=new JButton("悔棋");
jf.add(jb2);
jb2.setBounds(675, 265, 100,40);
jb2.addActionListener(mouse);
JButton jb3=new JButton("人机对战");
jf.add(jb3);
jb3.setBounds(675, 345, 100,40);
jb3.addActionListener(mouse);
//棋盘对象
ChessJpanel cp = new ChessJpanel();
//cp.setBackground(Color.ORANGE);
jf.add(cp,BorderLayout.CENTER);
cp.setOpaque(false);
cp.addMouseListener(mouse);
cp.addMouseMotionListener(mouse);
jf.setVisible(true);
Graphics g=cp.getGraphics();
mouse.setgr(g);
mouse.setcp(cp);
cp.setMouse(mouse);
}
}
我们在界面的底层容器加上了背景图片,添加了几个功能按键,设置了其坐标和大小。创建了一些对象,调用了相应传递对象的方法。并添加了若干监听器。
public class ChessJpanel extends JPanel implements Config{
private Shape[] arrayshape;
private DrawMouse mouse;
public void setarray(Shape[] arrayshape)
{
this.arrayshape=arrayshape;
}
public void setMouse(DrawMouse mouse)
{
this.mouse=mouse;
}
public void paint (Graphics g)
{
super.paint(g);
ImageIcon img = new ImageIcon("E:\\workspace\\mayifan\\src\\com\\myf\\gobang1030\\muban.jpg");//加载图片,绘制图片
g.drawImage(img.getImage(), 175, 80, 455, 455, null);
for(int i=0;i<LINE;i++)
{
g.drawLine(X0, Y0+i*SIZE, X0+(LINE-1)*SIZE, Y0+i*SIZE);
g.drawLine(X0+i*SIZE, Y0, X0+i*SIZE, Y0+(LINE-1)*SIZE);
}
g.drawLine(X0-10,Y0-10,X0+(LINE-1)*SIZE+10,Y0-10);
g.drawLine(X0-10,Y0+(LINE-1)*SIZE+10,X0+(LINE-1)*SIZE+10,Y0+(LINE-1)*SIZE+10);
g.drawLine(X0-10,Y0-10,X0-10,Y0+(LINE-1)*SIZE+10);
g.drawLine(X0+(LINE-1)*SIZE+10,Y0-10,X0+(LINE-1)*SIZE+10,Y0+(LINE-1)*SIZE+10);
for(int i=0;i<mouse.index;i++)
{
Shape shape=arrayshape[i];
if(shape!=null)
{
shape.drawShape(g);
}
else
break;
}
}
public void paint1 (Graphics g)
{
super.paint(g);
ImageIcon img1 = new ImageIcon("E:\\workspace\\mayifan\\src\\com\\myf\\gobang1030\\muban.jpg");//加载图片,绘制图片
g.drawImage(img1.getImage(), 175, 80, 455, 455, null);
for(int i=0;i<LINE;i++)
{
g.drawLine(X0, Y0+i*SIZE, X0+(LINE-1)*SIZE, Y0+i*SIZE);
g.drawLine(X0+i*SIZE, Y0, X0+i*SIZE, Y0+(LINE-1)*SIZE);
}
g.drawLine(X0-10,Y0-10,X0+(LINE-1)*SIZE+10,Y0-10);
g.drawLine(X0-10,Y0+(LINE-1)*SIZE+10,X0+(LINE-1)*SIZE+10,Y0+(LINE-1)*SIZE+10);
g.drawLine(X0-10,Y0-10,X0-10,Y0+(LINE-1)*SIZE+10);
g.drawLine(X0+(LINE-1)*SIZE+10,Y0-10,X0+(LINE-1)*SIZE+10,Y0+(LINE-1)*SIZE+10);
}
}
这里我们写了两个paint函数,一个用于恢复初始的棋盘,一个用于恢复棋盘以及棋子(防止最小化或者窗口伸缩导致画面丢失),我们通过循环绘制棋盘线条和棋子。其中基本上所有参数都来自于接口中定义的属性。
值得一提的是我们用到了HashMap:
HashMap <String,Integer> map =new HashMap<>();
它的作用是用来做数据的存储和调用,创建权值表:
例如:HashMap
<>:泛型(泛指类:类,接口,数组)
hm.put(“1”,20);
hm.put(“11”,200);
hm.put(“111”,2000);
使用方法很简单,通过 hm.get(111);即可获取参数2000。
HashMap在代码中的作用就是为各种棋局赋相应的权值,然后通过遍历的方法,做棋局分析,实现AI。我们本次的思路就是遍历棋盘所有的空格,分别对其“上,下,左,右,左上,左下,右上,右下”八个方向进行棋局判断,即从相邻子开始读取并判断存值,把八个方向的权值相加,便可以得到本空位的权值,遍历棋盘可得到权值最大的空位。自然,权值分为进攻和防守两种,假如执黑子,进攻的权值需要看连续黑子的数量,防守权值需要看连续白子的数量,最终要把进攻最大权值和防守最大权值进行比较,选择进攻或者防守,这样一来电脑就可以代替人去“思考”了。仔细一想,确实,电脑的行棋思路也很符合我们的思维习惯,通过观察棋局来判断是该进攻还是防守,以及该在何处落子。
接下来我们先贴监听器类的完整代码,再分别介绍各个方法的作用。
public class DrawMouse implements ActionListener, MouseMotionListener, MouseListener, Config {
private int x, y, z;
public int x1,y1;
private int point_x, point_y;
private Graphics g;
private int turn = 0;//0:黑子 1:白子
private ChessJpanel cp;
private int flagStart = 0;
private Shape[] arrayshape = new Shape[250];
public int index = 0;
public int winFlag=0;
public int flagAi=0;
public int xMax=0;
public int yMax=0;
public int xMax1=0;
public int yMax1=0;
public int weightMax=0;
public int weightMax1=0;
public int random;
int add=1;
private Color color = Color.BLACK;
int value[][] = new int[LINE][LINE];// 0:未存 1:黑 2:白 3:边界
HashMap <String,Integer> map =new HashMap<>();
public void setgr(Graphics g) {
this.g = g;
}
public void setcp(ChessJpanel cp) {
this.cp = cp;
this.cp.setarray(arrayshape);
}
public void actionPerformed(ActionEvent e)
{
if ("新游戏".equals(e.getActionCommand()))
{
System.out.println("新游戏");
turn=0;
cp.paint1(g);
flagStart = 1;
winFlag=0;
index=0;
for(int i=0;i<LINE;i++)
{
for(int j=0;j<LINE;j++)
{
value[i][j]=0;
}
}
if(flagAi==1)
{
random=1+(int)(Math.random()*2);
if(random==1)//AI 先手,执黑子
{
map.put("11110", AI_A_1);//活四连 初始化权重
map.put("11112", AI_A_2);//死四连
map.put("11113", AI_A_3);
map.put("1110",AI_A_4);//活三连
map.put("1112",AI_A_5);//死三连
map.put("1113",AI_A_6);
map.put("110",AI_A_7);//活二连
map.put("112",AI_A_8);//死二连
map.put("113",AI_A_9);
map.put("10",AI_A_10);//活一连
map.put("12",AI_A_11);//死一连
map.put("13",AI_A_12);
map.put("2", AI_A_13);
map.put("0", AI_1);
map.put("3", AI_2);
map.put("22220", AI_G_1);
map.put("22221", AI_G_2);
map.put("22223", AI_G_3);
map.put("2220", AI_G_4);
map.put("2221", AI_G_5);
map.put("2223", AI_G_6);
map.put("220", AI_G_7);
map.put("221", AI_G_8);
map.put("223", AI_G_9);
map.put("20", AI_G_10);
map.put("21", AI_G_11);
map.put("23", AI_G_12);
map.put("1", AI_G_13);
value[LINE/2][LINE/2]=1;
g.setColor(Color.BLACK);
g.drawOval(X0+(LINE/2)*SIZE-CHESS_SIZE/2, Y0+(LINE/2)*SIZE-CHESS_SIZE/2, CHESS_SIZE,CHESS_SIZE);
g.fillOval(X0+(LINE/2)*SIZE-CHESS_SIZE/2, Y0+(LINE/2)*SIZE-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
setShape(X0+(LINE/2)*SIZE, Y0+(LINE/2)*SIZE,g.getColor());
turn=1;
}
else if(random==2) //AI后手 AI执白子
{
map.put("11110", AI_G_1);//活四连 初始化权重
map.put("11112", AI_G_2);//死四连
map.put("11113", AI_G_3);
map.put("1110",AI_G_4);//活三连
map.put("1112",AI_G_5);//死三连
map.put("1113",AI_G_6);
map.put("110",AI_G_7);//活二连
map.put("112",AI_G_8);//死二连
map.put("113",AI_G_9);
map.put("10",AI_G_10);//活一连
map.put("12",AI_G_11);//死一连
map.put("13",AI_G_12);
map.put("2",AI_G_13);
map.put("0", AI_1);
map.put("3", AI_2);
map.put("22220", AI_A_1);
map.put("22221", AI_A_2);
map.put("22223", AI_A_3);
map.put("2220", AI_A_4);
map.put("2221", AI_A_5);
map.put("2223", AI_A_6);
map.put("220", AI_A_7);
map.put("221", AI_A_8);
map.put("223", AI_A_9);
map.put("20", AI_A_10);
map.put("21", AI_A_11);
map.put("23", AI_A_12);
map.put("1", AI_A_13);
}
}
}
if("悔棋".equals(e.getActionCommand()))
{
if(index>1)
{
value[(arrayshape[index-1].y1-Y0)/SIZE][(arrayshape[index-1].x1-X0)/SIZE]=0;
index--;
cp.paint(g);
if(turn==0)
turn=1;
else
turn=0;
if(flagAi==1)
{
value[(arrayshape[index-1].y1-Y0)/SIZE][(arrayshape[index-1].x1-X0)/SIZE]=0;
index--;
cp.paint(g);
if(turn==0)
turn=1;
else
turn=0;
}
}
}
if("人机对战".equals(e.getActionCommand()))
{
if(flagAi==0)
{
flagAi=1;
System.out.println("人机打开");
System.out.println("开始游戏");
turn=0;
cp.paint1(g);
flagStart = 1;
winFlag=0;
index=0;
for(int i=0;i<LINE;i++)
{
for(int j=0;j<LINE;j++)
{
value[i][j]=0;
}
}
}
else
{
flagAi=0;
System.out.println("人机关闭");
}
if(flagAi==1)
{
random=1+(int)(Math.random()*2);
if(random==1)//AI 先手,执黑子
{
map.put("11110", AI_A_1);//活四连 初始化权重
map.put("11112", AI_A_2);//死四连
map.put("11113", AI_A_3);
map.put("1110",AI_A_4);//活三连
map.put("1112",AI_A_5);//死三连
map.put("1113",AI_A_6);
map.put("110",AI_A_7);//活二连
map.put("112",AI_A_8);//死二连
map.put("113",AI_A_9);
map.put("10",AI_A_10);//活一连
map.put("12",AI_A_11);//死一连
map.put("13",AI_A_12);
map.put("2", AI_A_13);
map.put("0", AI_1);
map.put("3", AI_2);
map.put("22220", AI_G_1);
map.put("22221", AI_G_2);
map.put("22223", AI_G_3);
map.put("2220", AI_G_4);
map.put("2221", AI_G_5);
map.put("2223", AI_G_6);
map.put("220", AI_G_7);
map.put("221", AI_G_8);
map.put("223", AI_G_9);
map.put("20", AI_G_10);
map.put("21", AI_G_11);
map.put("23", AI_G_12);
map.put("1", AI_G_13);
value[LINE/2][LINE/2]=1;
g.setColor(Color.BLACK);
g.drawOval(X0+(LINE/2)*SIZE-CHESS_SIZE/2, Y0+(LINE/2)*SIZE-CHESS_SIZE/2, CHESS_SIZE,CHESS_SIZE);
g.fillOval(X0+(LINE/2)*SIZE-CHESS_SIZE/2, Y0+(LINE/2)*SIZE-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
setShape(X0+(LINE/2)*SIZE, Y0+(LINE/2)*SIZE,g.getColor());
turn=1;
}
else if(random==2) //AI后手 AI执白子
{
map.put("11110", AI_G_1);//活四连 初始化权重
map.put("11112", AI_G_2);//死四连
map.put("11113", AI_G_3);
map.put("1110",AI_G_4);//活三连
map.put("1112",AI_G_5);//死三连
map.put("1113",AI_G_6);
map.put("110",AI_G_7);//活二连
map.put("112",AI_G_8);//死二连
map.put("113",AI_G_9);
map.put("10",AI_G_10);//活一连
map.put("12",AI_G_11);//死一连
map.put("13",AI_G_12);
map.put("2",AI_G_13);
map.put("0", AI_1);
map.put("3", AI_2);
map.put("22220", AI_A_1);
map.put("22221", AI_A_2);
map.put("22223", AI_A_3);
map.put("2220", AI_A_4);
map.put("2221", AI_A_5);
map.put("2223", AI_A_6);
map.put("220", AI_A_7);
map.put("221", AI_A_8);
map.put("223", AI_A_9);
map.put("20", AI_A_10);
map.put("21", AI_A_11);
map.put("23", AI_A_12);
map.put("1", AI_A_13);
}
}
}
}
public void mouseDragged(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
public void mouseClicked(MouseEvent e)
{
x=e.getX();
y=e.getY();
if(x>X0&&x<(X0+SIZE*(LINE-1))&&y>Y0&&y<(Y0+SIZE*(LINE-1)))
{
z=(x-X0)/SIZE;
z=X0+z*SIZE;
if(Math.abs(x-z)>=0.5*SIZE)
{
x=(((x-X0)/SIZE)+1)*SIZE+X0;
point_x=((x-X0)/SIZE);
}
else
{
x=(((x-X0)/SIZE))*SIZE+X0;
point_x=((x-X0)/SIZE);
}
z=(y-Y0)/SIZE;
z=Y0+z*SIZE;
if(Math.abs(y-z)>=0.5*SIZE)
{
y=(((y-Y0)/SIZE)+1)*SIZE+Y0;
point_y=((y-Y0)/SIZE);
}
else
{
y=(((y-Y0)/SIZE))*SIZE+Y0;
point_y=((y-Y0)/SIZE);
}
if(flagStart==1&&value[point_y][point_x]==0)
{
if(turn==0)
{
g.setColor(Color.BLACK);
value[point_y][point_x]=1;
checkWin();
}
else
{
g.setColor(Color.WHITE);
value[point_y][point_x]=2;
checkWin();
}
if(turn==0)
turn=1;
else
turn=0;
g.drawOval(x-CHESS_SIZE/2, y-CHESS_SIZE/2, CHESS_SIZE,CHESS_SIZE);
g.fillOval(x-CHESS_SIZE/2, y-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
setShape(x,y,g.getColor());
}
}
if(flagAi==1&&flagStart==1)
AiChess();
}
public void AiChess()
{
AI();
AI1();
if(weightMax>weightMax1)
{
x=xMax;
y=yMax;
}
else
{
x=xMax1;
y=yMax1;
}
if(x>X0&&x<(X0+SIZE*(LINE-1))&&y>Y0&&y<(Y0+SIZE*(LINE-1)))
{
z=(x-X0)/SIZE;
z=X0+z*SIZE;
if(Math.abs(x-z)>=0.5*SIZE)
{
x=(((x-X0)/SIZE)+1)*SIZE+X0;
point_x=((x-X0)/SIZE);
}
else
{
x=(((x-X0)/SIZE))*SIZE+X0;
point_x=((x-X0)/SIZE);
}
z=(y-Y0)/SIZE;
z=Y0+z*SIZE;
if(Math.abs(y-z)>=0.5*SIZE)
{
y=(((y-Y0)/SIZE)+1)*SIZE+Y0;
point_y=((y-Y0)/SIZE);
}
else
{
y=(((y-Y0)/SIZE))*SIZE+Y0;
point_y=((y-Y0)/SIZE);
}
if(flagStart==1&&value[point_y][point_x]==0)
{
if(turn==0)//黑子
{
g.setColor(Color.BLACK);
value[point_y][point_x]=1;
checkWin();
}
else //白子
{
g.setColor(Color.WHITE);
value[point_y][point_x]=2;
checkWin();
}
if(turn==0)
turn=1;
else
turn=0;
g.drawOval(x-CHESS_SIZE/2, y-CHESS_SIZE/2, CHESS_SIZE,CHESS_SIZE);
g.fillOval(x-CHESS_SIZE/2, y-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
setShape(x,y,g.getColor());
}
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void setShape(int x1, int y1, Color color) {
Shape shape = new Shape(x1, y1, color);
arrayshape[index++] = shape;
}
public void checkWin()
{
if(g.getColor().equals(Color.black))
{
add=1;
for(int i=1;i<5;i++)//水平
{
if(point_x-i<0)
break;
if(value[point_y][point_x-i]==1)//左方向
add++;
if(value[point_y][point_x-i]!=1)
break;
}
for(int i=1;i<5;i++)//水平
{
if(point_x+i>LINE-1)
break;
if(value[point_y][point_x+i]==1)//右方向
add++;
if(value[point_y][point_x+i]!=1)
break;
}
if(add==5)
winFlag=1;
add=1;
for(int i=1;i<5;i++)//竖直
{
if(point_y-i<0)
break;
if(value[point_y-i][point_x]==1)//上方向
add++;
if(value[point_y-i][point_x]!=1)
break;
}
for(int i=1;i<5;i++)//竖直
{
if(point_y+i>LINE-1)
break;
if(value[point_y+i][point_x]==1)//下方向
add++;
if(value[point_y+i][point_x]!=1)
break;
}
if(add==5)
winFlag=1;
add=1;
for(int i=1;i<5;i++)//斜方向
{
if(point_y-i<0||point_x-i<0)
break;
if(value[point_y-i][point_x-i]==1)//左上
add++;
if(value[point_y-i][point_x-i]!=1)
break;
}
for(int i=1;i<5;i++)//斜方向
{
if(point_y+i>LINE-1||point_x+i>LINE-1)
break;
if(value[point_y+i][point_x+i]==1)//右下
add++;
if(value[point_y+i][point_x+i]!=1)
break;
}
if(add==5)
winFlag=1;
add=1;
for(int i=1;i<5;i++)//斜方向
{
if(point_y+i>LINE-1||point_x-i<0)
break;
if(value[point_y+i][point_x-i]==1)//左下
add++;
if(value[point_y+i][point_x-i]!=1)
break;
}
for(int i=1;i<5;i++)//斜方向
{
if(point_y-i<0||point_x+i>LINE-1)
break;
if(value[point_y-i][point_x+i]==1)//右上
add++;
if(value[point_y-i][point_x+i]!=1)
break;
}
if(add==5)
winFlag=1;
if(winFlag==1)
{
System.out.println("黑子胜");
System.out.println("比赛结束");
blackWin();
flagStart = 0;
winFlag=0;
}
}
if(g.getColor().equals(Color.WHITE))
{
add=1;
for(int i=1;i<5;i++)//水平
{
if(point_x-i<0)
break;
if(value[point_y][point_x-i]==2)//左方向
add++;
if(value[point_y][point_x-i]!=2)
break;
}
for(int i=1;i<5;i++)//水平
{
if(point_x+i>LINE-1)
break;
if(value[point_y][point_x+i]==2)//右方向
add++;
if(value[point_y][point_x+i]!=2)
break;
}
if(add==5)
winFlag=2;
add=1;
for(int i=1;i<5;i++)//竖直
{
if(point_y-i<0)
break;
if(value[point_y-i][point_x]==2)//上方向
add++;
if(value[point_y-i][point_x]!=2)
break;
}
for(int i=1;i<5;i++)//竖直
{
if(point_y+i>LINE-1)
break;
if(value[point_y+i][point_x]==2)//下方向
add++;
if(value[point_y+i][point_x]!=2)
break;
}
if(add==5)
winFlag=2;
add=1;
for(int i=1;i<5;i++)//斜方向
{
if(point_y-i<0||point_x-i<0)
break;
if(value[point_y-i][point_x-i]==2)//左上
add++;
if(value[point_y-i][point_x-i]!=2)
break;
}
for(int i=1;i<5;i++)//斜方向
{
if(point_y+i>LINE-1||point_x+i>LINE-1)
break;
if(value[point_y+i][point_x+i]==2)//右下
add++;
if(value[point_y+i][point_x+i]!=2)
break;
}
if(add==5)
winFlag=2;
add=1;
for(int i=1;i<5;i++)//斜方向
{
if(point_y+i>LINE-1||point_x-i<0)
break;
if(value[point_y+i][point_x-i]==2)//左下
add++;
if(value[point_y+i][point_x-i]!=2)
break;
}
for(int i=1;i<5;i++)//斜方向
{
if(point_y-i<0||point_x+i>LINE-1)
break;
if(value[point_y-i][point_x+i]==2)//右上
add++;
if(value[point_y-i][point_x+i]!=2)
break;
}
if(add==5)
winFlag=2;
if(winFlag==2)
{
System.out.println("白子胜");
System.out.println("比赛结束");
whiteWin();
flagStart = 0;
winFlag=0;
}
}
add=1;
winFlag=0;
}
public void blackWin()
{
javax.swing.JFrame jf2 = new javax.swing.JFrame();
jf2.setSize(400, 300);
jf2.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
jf2.setLocationRelativeTo(null);
java.awt.FlowLayout flow = new java.awt.FlowLayout();
jf2.setLayout(flow);
javax.swing.ImageIcon Page = new javax.swing.ImageIcon("E:\\workspace\\mayifan\\src\\com\\myf\\gobang1030\\black.png");
javax.swing.JLabel jla = new javax.swing.JLabel(Page);
java.awt.Dimension du = new java.awt.Dimension(400, 300);
jla.setPreferredSize(du);
jf2.add(jla);
jf2.setVisible(true);
}
public void whiteWin()
{
javax.swing.JFrame jf1 = new javax.swing.JFrame();
jf1.setSize(400, 300);
jf1.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
jf1.setLocationRelativeTo(null);
java.awt.FlowLayout flow = new java.awt.FlowLayout();
jf1.setLayout(flow);
javax.swing.ImageIcon Page = new javax.swing.ImageIcon("E:\\workspace\\mayifan\\src\\com\\myf\\gobang1030\\white.png");
javax.swing.JLabel jla = new javax.swing.JLabel(Page);
java.awt.Dimension du = new java.awt.Dimension(400, 300);
jla.setPreferredSize(du);
jf1.add(jla);
jf1.setVisible(true);
}
public void AI() //进攻形势
{
int chess=0;
int weight=0;
int weightArr[][] = new int[LINE][LINE];//保存每个位置的权重
String qiju="";
weightMax=0;
for(int i=0;i<LINE;i++)
{
for(int j=0;j<LINE;j++)
{
if(value[i][j]!=0)
continue;
else
{
for(int k=1;k<6;k++)//向上
{
if(i-k<0)
{
chess=3;
qiju+=chess;
break;
}
chess=value[i-k][j];
if(chess==0)
{
qiju+=chess;
break;
}
else if(chess==1)
{
qiju+=chess;
}
else if(chess==2)
{
qiju+=chess;
break;
}
}
weight=map.get(qiju);
weightArr[i][j]+=weight;
qiju="";
for(int k=1;k<6;k++)//向下
{
if(i+k>LINE-1)
{
chess=3;
qiju+=chess;
break;
}
chess=value[i+k][j];
if(chess==0)
{
qiju+=chess;
break;
}
else if(chess==1)
{
qiju+=chess;
}
else if(chess==2)
{
qiju+=chess;
break;
}
}
weight=map.get(qiju);
weightArr[i][j]+=weight;
qiju="";
for(int k=1;k<6;k++)//向左
{
if(j-k<0)
{
chess=3;
qiju+=chess;
break;
}
chess=value[i][j-k];
if(chess==0)
{
qiju+=chess;
break;
}
else if(chess==1)
{
qiju+=chess;
}
else if(chess==2)
{
qiju+=chess;
break;
}
}
weight=map.get(qiju);
weightArr[i][j]+=weight;
qiju="";
for(int k=1;k<6;k++)//向右
{
if(j+k>LINE-1)
{
chess=3;
qiju+=chess;
break;
}
chess=value[i][j+k];
if(chess==0)
{
qiju+=chess;
break;
}
else if(chess==1)
{
qiju+=chess;
}
else if(chess==2)
{
qiju+=chess;
break;
}
}
weight=map.get(qiju);
weightArr[i][j]+=weight;
qiju="";
for(int k=1;k<6;k++)//向左上
{
if(i-k<0||j-k<0)
{
chess=3;
qiju+=chess;
break;
}
chess=value[i-k][j-k];
if(chess==0)
{
qiju+=chess;
break;
}
else if(chess==1)
{
qiju+=chess;
}
else if(chess==2)
{
qiju+=chess;
break;
}
}
weight=map.get(qiju);
weightArr[i][j]+=weight;
qiju="";
for(int k=1;k<6;k++)//向右下
{
if(i+k>LINE-1||j+k>LINE-1)
{
chess=3;
qiju+=chess;
break;
}
chess=value[i+k][j+k];
if(chess==0)
{
qiju+=chess;
break;
}
else if(chess==1)
{
qiju+=chess;
}
else if(chess==2)
{
qiju+=chess;
break;
}
}
weight=map.get(qiju);
weightArr[i][j]+=weight;
qiju="";
for(int k=1;k<6;k++)//向左下
{
if(i+k>LINE-1||j-k<0)
{
chess=3;
qiju+=chess;
break;
}
chess=value[i+k][j-k];
if(chess==0)
{
qiju+=chess;
break;
}
else if(chess==1)
{
qiju+=chess;
}
else if(chess==2)
{
qiju+=chess;
break;
}
}
weight=map.get(qiju);
weightArr[i][j]+=weight;
qiju="";
for(int k=1;k<6;k++)//向右上
{
if(i-k<0||j+k>LINE-1)
{
chess=3;
qiju+=chess;
break;
}
chess=value[i-k][j+k];
if(chess==0)
{
qiju+=chess;
break;
}
else if(chess==1)
{
qiju+=chess;
}
else if(chess==2)
{
qiju+=chess;
break;
}
}
weight=map.get(qiju);
weightArr[i][j]+=weight;
qiju="";
}
if(weightArr[i][j]>weightMax)
{
weightMax=weightArr[i][j];
xMax=j*SIZE+X0;
yMax=i*SIZE+Y0;
//System.out.println(weightMax);
//System.out.println(i);
//System.out.println(j);
}
}
}
}
public void AI1()
{
int chess1=0;
int weight1=0;
int weightArr1[][] = new int[LINE][LINE];//保存每个位置的权重
String qiju1="";
weightMax1=0;
for(int i=0;i<LINE;i++)
{
for(int j=0;j<LINE;j++)
{
if(value[i][j]!=0)
continue;
else
{
for(int k=1;k<6;k++)//向上
{
if(i-k<0)
{
chess1=3;
qiju1+=chess1;
break;
}
chess1=value[i-k][j];
if(chess1==0)
{
qiju1+=chess1;
break;
}
else if(chess1==1)
{
qiju1+=chess1;
break;
}
else if(chess1==2)
{
qiju1+=chess1;
}
}
weight1=map.get(qiju1);
weightArr1[i][j]+=weight1;
qiju1="";
for(int k=1;k<6;k++)//向下
{
if(i+k>LINE-1)
{
chess1=3;
qiju1+=chess1;
break;
}
chess1=value[i+k][j];
if(chess1==0)
{
qiju1+=chess1;
break;
}
else if(chess1==1)
{
qiju1+=chess1;
break;
}
else if(chess1==2)
{
qiju1+=chess1;
}
}
weight1=map.get(qiju1);
weightArr1[i][j]+=weight1;
qiju1="";
for(int k=1;k<6;k++)//向左
{
if(j-k<0)
{
chess1=3;
qiju1+=chess1;
break;
}
chess1=value[i][j-k];
if(chess1==0)
{
qiju1+=chess1;
break;
}
else if(chess1==1)
{
qiju1+=chess1;
break;
}
else if(chess1==2)
{
qiju1+=chess1;
}
}
weight1=map.get(qiju1);
weightArr1[i][j]+=weight1;
qiju1="";
for(int k=1;k<6;k++)//向右
{
if(j+k>LINE-1)
{
chess1=3;
qiju1+=chess1;
break;
}
chess1=value[i][j+k];
if(chess1==0)
{
qiju1+=chess1;
break;
}
else if(chess1==1)
{
qiju1+=chess1;
break;
}
else if(chess1==2)
{
qiju1+=chess1;
}
}
weight1=map.get(qiju1);
weightArr1[i][j]+=weight1;
qiju1="";
for(int k=1;k<6;k++)//向左上
{
if(i-k<0||j-k<0)
{
chess1=3;
qiju1+=chess1;
break;
}
chess1=value[i-k][j-k];
if(chess1==0)
{
qiju1+=chess1;
break;
}
else if(chess1==1)
{
qiju1+=chess1;
break;
}
else if(chess1==2)
{
qiju1+=chess1;
}
}
weight1=map.get(qiju1);
weightArr1[i][j]+=weight1;
qiju1="";
for(int k=1;k<6;k++)//向右下
{
if(i+k>LINE-1||j+k>LINE-1)
{
chess1=3;
qiju1+=chess1;
break;
}
chess1=value[i+k][j+k];
if(chess1==0)
{
qiju1+=chess1;
break;
}
else if(chess1==1)
{
qiju1+=chess1;
break;
}
else if(chess1==2)
{
qiju1+=chess1;
}
}
weight1=map.get(qiju1);
weightArr1[i][j]+=weight1;
qiju1="";
for(int k=1;k<6;k++)//向左下
{
if(i+k>LINE-1||j-k<0)
{
chess1=3;
qiju1+=chess1;
break;
}
chess1=value[i+k][j-k];
if(chess1==0)
{
qiju1+=chess1;
break;
}
else if(chess1==1)
{
qiju1+=chess1;
break;
}
else if(chess1==2)
{
qiju1+=chess1;
}
}
weight1=map.get(qiju1);
weightArr1[i][j]+=weight1;
qiju1="";
for(int k=1;k<6;k++)//向右上
{
if(i-k<0||j+k>LINE-1)
{
chess1=3;
qiju1+=chess1;
break;
}
chess1=value[i-k][j+k];
if(chess1==0)
{
qiju1+=chess1;
break;
}
else if(chess1==1)
{
qiju1+=chess1;
break;
}
else if(chess1==2)
{
qiju1+=chess1;
}
}
weight1=map.get(qiju1);
weightArr1[i][j]+=weight1;
qiju1="";
}
if(weightArr1[i][j]>weightMax1)
{
weightMax1=weightArr1[i][j];
xMax1=j*SIZE+X0;
yMax1=i*SIZE+Y0;
//System.out.println(weightMax);
//System.out.println(i+" "+j);
}
}
}
}
}
代码很长,如果大家有优化的思路,很欢迎大家在评论区提出意见。
public void actionPerformed(ActionEvent e):此方法为按钮写了具体的监听器方法,按下“新游戏”可以开始游戏,若没有开启人机,则初始化棋盘令黑子先下,然后白子。若开启人机,则可随机分配先手方,并为人机分配权值。“悔棋”功能可以实现倒退任意步棋子的功能。“人机对战”开启后可重新分配先手并清空棋盘,若比赛中途按下,可关闭人机。
public void mouseClicked(MouseEvent e):执行落子操作,获取坐标,判断落子的具体地点,判断黑白方,判断此处之前有无落子。整个棋盘的每个可落子点都被数组编码,1是黑子,2是白子,3是边界,0是空位。
public void AiChess();人机和人其实没有很大的区别,人落子的方法依然可以应用于电脑。不过是换了触发方式,人通过鼠标点击,电脑通过方法调用。若人机的开关打开,则在人落子后,调用电脑落子的方法。其中的内容,其实如出一辙。
public void setShape(int x1, int y1, Color color):每次落子后都调用这个方法保存棋子对象,便于悔棋和画面恢复。
public void checkWin():每次落子后都要判断输赢,调用这个方法。思路是通过最后一个落子向八个方向遍历判断有无5个子。
public void blackWin()和public void whiteWin():两个方法写的是输赢的弹出窗口。在判断输赢后调用,可手动关闭。
public void AI()和public void AI1()分别是进攻权值和防守权值的计算方法。两个都要调用一遍,以进行攻防判断。
以下我们再贴出接口类的代码:
public interface Config {
public static final int X0=192; //棋盘左上角坐标
public static final int Y0=97;
public static final int SIZE=30; //格子宽
public static final int LINE=15; //行列数
public static final int CHESS_SIZE=28;//棋子的大小
//AI进攻 0:空 1:黑子 2:白子 3:边界
public static final int AI_A_1=20000; // AI黑:11110 AI白:22220
public static final int AI_A_2=18000; // AI黑:11112 AI白:22221
public static final int AI_A_3=17000; // AI黑:11113 AI白:22223
public static final int AI_A_4=10000; // AI黑:1110 AI白:2220
public static final int AI_A_5=650; // AI黑:1112 AI白:2221
public static final int AI_A_6=600; // AI黑:1113 AI白:2223
public static final int AI_A_7=400; // AI黑:110 AI白:220
public static final int AI_A_8=270; // AI黑:112 AI白:221
public static final int AI_A_9=250; // AI黑:113 AI白:223
public static final int AI_A_10=200; // AI黑:10 AI白:20
public static final int AI_A_11=120; // AI黑:12 AI白:21
public static final int AI_A_12=100; // AI黑:13 AI白:23
public static final int AI_A_13=40; // AI黑:2 AI白:1
//AI防守
public static final int AI_G_1=11000; // AI黑:22220 AI白:11110
public static final int AI_G_2=16000; // AI黑:22221 AI白:11112
public static final int AI_G_3=15000; // AI黑:22223 AI白:11113
public static final int AI_G_4=5000; // AI黑:2220 AI白:1110
public static final int AI_G_5=600; // AI黑:2221 AI白:1112
public static final int AI_G_6=550; // AI黑:2223 AI白:1113
public static final int AI_G_7=500; // AI黑:220 AI白:110
public static final int AI_G_8=220; // AI黑:221 AI白:112
public static final int AI_G_9=200; // AI黑:223 AI白:113
public static final int AI_G_10=100; // AI黑:20 AI白:10
public static final int AI_G_11=40; // AI黑:21 AI白:12
public static final int AI_G_12=30; // AI黑:23 AI白:13
public static final int AI_G_13=25; // AI黑:1 AI白:2
public static final int AI_1=20; //0
public static final int AI_2=10; //3
}
把权值定义在接口可以方便的在后期实战中对参数进行调整。里面也对各种情况进行了分类。
最后是Shape类的属性和方法:
public class Shape implements Config {
public int x1,y1;
private Color color;
public Shape(int x1,int y1,Color color)
{
this.x1=x1;
this.y1=y1;
this.color=color;
}
public void drawShape(Graphics g)
{
g.setColor(color);
g.drawOval(x1-CHESS_SIZE/2, y1-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
g.fillOval(x1-CHESS_SIZE/2, y1-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
}
}
以上是我五子棋程序的所有代码。优化程序以及完善算法会是我之后可以去尝试去做的。人工智能势必引起一股热潮,我们每个人都应该学习算法,培养自己思考问题的能力,把许多现实事物转化到0和1的世界。
最后贴上几张我五子棋的程序运行截图。