创建一个窗体来承载五子棋
如何创建一个窗体,以及如何在窗体上添加必要的按钮组件等操作,可以查看我的第一篇文章,里面有详细的讲解,这里就不在重新累述。具体的代码如下:
public class DrawUI{
public void ShowUI(){
MyFrame jf=new MyFrame();//这里原本应该是使用JFrame但,后续重绘中创建了子类MyFrame继承父类JFrame,这里就换成了MyFrame
//设置窗体属性
jf.setSize(500,500);
jf.setLocationRelativeTo(null);
jf.setTitle("五子棋");
jf.setResizable(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout fl=new FlowLayout();//设置窗体格式
jf.setLayout(fl);
JButton jb=new JButton("人人对战");//添加按钮
JButton jb1=new JButton("悔棋");
JButton jb2=new JButton("清空棋盘");
JButton jb3=new JButton("人机对战");
jf.add(jb);
jf.add(jb1);
jf.add(jb2);
jf.add(jb3);
jf.setVisible(true);
Graphics g=jf.getGraphics();//给窗体添加画笔
UIListener ul=new UIListener();
jb.addActionListener(ul);//给按钮添加监听器
jb1.addActionListener(ul);
jb2.addActionListener(ul);
jb3.addActionListener(ul);
jf.addMouseListener(ul);//给窗体添加监听器
ul.gr=g;//将画笔倒给UIlistener中的gr
jf.ul=ul;//为了在Myframe中使用ChessArray,将UIistener中的ul倒给Myframe中的ul
ul.jb11=jb;//将按钮jb倒给ul中的jb11,方便其使用jb
ul.mf=jf;//为了在UIlistener中重绘,将jf倒给其中的mf
}
}
五子棋基本程序编写
绘制棋盘
第一步肯定是要在创建好的窗体上绘制出五子棋的棋盘。思路也很简单,就是画出横竖两条线,然后设置一个固定间隔,不断循环,绘制出一个棋盘。
这里注意,因为如果只是在窗体中绘制出棋盘,那么每次窗体被拖动,刷新后,窗体中的绘制好的棋盘就会被刷新掉,所以需要重绘,确保棋盘永久存在,所以在这里,我们就直接将棋盘绘制在窗体重绘方法中。
public class MyFrame extends JFrame{//MyFrame子类继承JFrame父类
public void paint(Graphics g) {//重绘棋盘,确保刷新网页时候,棋盘还在
super.paint(g);
int x1,x2,y1,y2;
int X1,X2,Y1,Y2;
x1=50;x2=450;y1=70;y2=470;
X1=50;X2=450;Y1=70;Y2=470;
for(int i=0; i<21; i++) {
g.drawLine(x1,y1,x2,y1);
y1=y1+20;
}
for(int i=0; i<21; i++) {
g.drawLine(X1,Y1,X1,Y2);
X1=X1+20;
}
}
}
这里也需要注意:因为重绘方法是需要写在MyFrame类中的,由于后续还会有需要重绘的东西,所以后续会在这部分继续扩充需要重绘的内容代码。
绘制棋子(人人对战中棋子黑白交替出现,人机对战中玩家下黑子,电脑下白子)
绘制棋子时候,我们应该能清楚思路。
首先,鼠标点击的位置,这个位置不一定正好是在棋盘的网格交汇处的节点上,我们就要将这个鼠标点击的坐标优化至附近的交汇节点上。原理也很简单,将鼠标点击获取的坐标,计算转化成其在哪两个焦点之间,然后将两个节点之间一分为二,如果坐标在前部分,则优化到前面的节点上,如果在后半部分,则优化到后面的节点上。
其次,将鼠标点击的坐标优化到棋盘网格节点上后,则需要在这个网格节点上绘制棋子即可,但这里我们会发现,程序中绘制的圆形图形的时候,输入的绘制坐标点是绘制出来圆形的外切长方形的左上角的坐标,并非是圆形的圆心坐标。这时同样需要优化,将坐标分别减去它的半径,就能优化在鼠标点击转化过来的网格点上。
最后,我们需要存储已经下过的棋子的信息,方便后续判定输赢,已经棋子重绘时使用。这里为了存储棋子信息,我们就可以设立一个二维数组,二维数组正好对应横竖棋盘的网格,我们可以将黑棋的数组值定为1,白棋的数组值定为2。那么没有棋子的地方的数组值就为默认的0.
具体来看代码:
public class UIListener implements MouseListener ,ActionListener{//监听器是接口
//后续可能会用到的一些变量
Graphics gr;
int[][] ChessArray=new int[22][22];//黑白棋子数组
int[][] ChessValue=new int[22][22];//AI人机中权值数组
JButton jb11;
int nb=0;
int count=0;
int a,b,x,y,X,Y;
JFrame mf;
HashMap<String,Integer> hm=new HashMap<String,Integer>();//设置AI人机中权值量表
public void mouseClicked(MouseEvent e) {
int z=50,c=20;
Color c1=new Color(0,0,0);
Color c2=new Color(255,255,255);
a=e.getX();b=e.getY();//获得鼠标点击坐标
if(nb==1) {//确定是否可以下棋
if((a-z)%c>c/2) {//帮助x轴上点击点优化到坐标格子上
x=(a-z)/c+1;
}else {
x=(a-z)/c;
}
if((b-z)%c>c/2) {//帮助y轴上点击点优化到坐标格子上
y=(b-z)/c+1;
}else {
y=(b-z)/c;
}
if(ChessArray[x][y]==0) {//确保棋子只能下在没有棋子的地方
if(zifu.equals("人机对战")) {
gr.setColor(c1);
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=1;
gr.setColor(c2);
AI();
}else if(zifu.equals("人人对战")) {
if(count==0) {
gr.setColor(c1);
count++;
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=1;//黑子数组值为1,方便重绘使用
}else if(count==1) {
gr.setColor(c2);
count--;
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=2;//白子数组值为21,方便重绘使用
}
}
}else{
System.out.println("该位置已有棋子");
}
}else {
System.out.println("请选择对战类型");
}
}
重绘棋子
在绘制出棋子后,我们同样需要去意识到,拖动窗体或者任何会让窗体刷新的操作后,已经下好的棋子都会消失,那么我们就需要在重绘方法中,同样加入棋子的重绘,也就是正在绘制棋盘这个标题下的代码行中加入重绘棋子的代码。
原理则是,因为我们设置了数组保存棋子,黑棋都赋值了1,白棋都赋值了2,那么我就遍历整个棋盘上上的所有数组,然后把数组等于1和2的都重绘出来即可。
加入了棋子重绘的代码后,整个重绘部分的代码就如下:
public class MyFrame extends JFrame{//MyFrame子类继承JFrame父类
public UIListener ul;
// int[][] ChessArray;
int z=50,c=20;
public void paint(Graphics g) {//重绘棋盘,确保刷新网页时候,棋盘还在
super.paint(g);
int x1,x2,y1,y2;
int X1,X2,Y1,Y2;
x1=50;x2=450;y1=70;y2=470;
X1=50;X2=450;Y1=70;Y2=470;
for(int i=0; i<21; i++) {
g.drawLine(x1,y1,x2,y1);
y1=y1+20;
}
for(int i=0; i<21; i++) {
g.drawLine(X1,Y1,X1,Y2);
X1=X1+20;
}
int[][] ChessArray = ul.ChessArray;
for(int i=0;i<ChessArray.length;i++) {//重绘棋子,网页刷新后,之前下过的棋子还在
for(int j=0;j<ChessArray.length;j++) {
if(ChessArray[i][j]==1) {
g.setColor(Color.black);
g.fillOval(i*c+z-10, j*c+z-10, 20, 20);
}
if(ChessArray[i][j]==2) {
g.setColor(Color.white);
g.fillOval(i*c+z-10, j*c+z-10, 20, 20);
}
}
}
}
}
判定输赢
当棋子都下好了之后,我们就需要在每下一颗棋子后进行输赢的判定。五子棋中,有五颗棋子连在一起即为获胜。因此我们就需要对横竖斜四个大方向上的棋子,进行查找判定。
原理则是因为黑棋的数组值都为1,白棋都为2,那么就在每一次所下棋子的地方为起点,向各个方向查找,每有一个相连的棋子是同色,设置一个变量count,count就加1,当count变为5时候,就证明有五个同色棋子相连,游戏就结束,如果所下棋子是黑棋,黑棋就获胜,如果所下棋子是白棋,白棋就获胜。
下列代码是判定寻找各个方向的同色棋子的方法:
public int Win1(int xx,int yy) {//判定横向棋子是否有相连的
int count1=0;
for(int i=xx-1;i>=0;i--) {
if(ChessArray[i][yy]==ChessArray[xx][yy]) {
count1++;
}else break;
}
for(int j=xx;j<ChessArray.length;j++) {
if(ChessArray[j][yy]==ChessArray[xx][yy]) {
count1++;
}else break;
}
return count1;
}
public int Win2(int xx,int yy) {//判定纵向棋子是否有相连的
int count2=0;
for(int n=yy-1;n>=0;n--) {
if(ChessArray[xx][n]==ChessArray[xx][yy]) {
count2++;
}else break;
}
for(int m=yy;m<ChessArray.length;m++) {
if(ChessArray[xx][m]==ChessArray[xx][yy]) {
count2++;
}else break;
}
return count2;
}
public int Win3(int xx,int yy) {//判定左下右上棋子是否有相连的
int count3=0;
for(int o=xx-1,p=yy+1;o>=0&&p<ChessArray.length;o--,p++) {
if(ChessArray[o][p]==ChessArray[xx][yy]) {
count3++;
}else break;
}
for(int o=xx,p=yy;o<ChessArray.length&&p>=0;o++,p--) {
if(ChessArray[o][p]==ChessArray[xx][yy]) {
count3++;
}else break;
}
return count3;
}
public int Win4(int xx,int yy) {//判定左上右下棋子是否有相连的
int count4=0;
for(int o=xx-1,p=yy-1;o>=0&&p>=0;o--,p--) {
if(ChessArray[o][p]==ChessArray[xx][yy]) {
count4++;
}else break;
}
for(int o=xx,p=yy;o<ChessArray.length&&p<ChessArray.length;o++,p++) {
if(ChessArray[o][p]==ChessArray[xx][yy]) {
count4++;
}else break;
}
return count4;
}
之后,在写完判定胜负方法后,我们需要在每次下棋后,去调用这些方法,判定是否获胜。也就是在绘制棋子这部分的代码片中,继续加上调用判定的方法代码。加上后,这部分的代码如下所示:
public class UIListener implements MouseListener ,ActionListener{//监听器是接口
Graphics gr;
int[][] ChessArray=new int[22][22];
int[][] ChessValue=new int[22][22];
JButton jb11;
int nb=0;
int count=0;
int a,b,x,y,X,Y;
JFrame mf;
HashMap<String,Integer> hm=new HashMap<String,Integer>();
public void mouseClicked(MouseEvent e) {
// int a,b,x,y,X,Y;
int z=50,c=20;
Color c1=new Color(0,0,0);
Color c2=new Color(255,255,255);
a=e.getX();b=e.getY();//获得鼠标点击坐标
if(nb==1) {//确定是否可以下棋
if((a-z)%c>c/2) {//帮助x轴上点击点优化到坐标格子上
x=(a-z)/c+1;
}else {
x=(a-z)/c;
}
if((b-z)%c>c/2) {//帮助y轴上点击点优化到坐标格子上
y=(b-z)/c+1;
}else {
y=(b-z)/c;
}
if(ChessArray[x][y]==0) {//确保棋子只能下在没有棋子的地方
if(zifu.equals("人机对战")) {
gr.setColor(c1);
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=1;
gr.setColor(c2);
AI();
}else if(zifu.equals("人人对战")) {
if(count==0) {
gr.setColor(c1);
count++;
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=1;//黑子数组值为1,方便重绘使用
}else if(count==1) {
gr.setColor(c2);
count--;
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=2;//白子数组值为21,方便重绘使用
}
}
}else{
System.out.println("该位置已有棋子");
}
}else {
System.out.println("请选择对战类型");
}
if(Win1(x,y)==5||Win2(x,y)==5||Win3(x,y)==5||Win4(x,y)==5) {//确定获胜标准
if(ChessArray[x][y]==1) {
nb=0;
JOptionPane.showMessageDialog(null, "黑棋胜利");
}else if(ChessArray[x][y]==2) {
nb=0;
JOptionPane.showMessageDialog(null, "白棋胜利");
}
}
当然这里要注意,这里判定的方法只能判定人人对战中的黑白棋子,以及人机对战中的玩家所下的黑色棋子,因为导入其中的x,y坐标是鼠标点击优化过来的,所以人机对战中电脑所下的白子不会调用这个方法,所以人机对战中的电脑白棋获胜判定我们会在电脑下棋方法AI中单独写一个。
人机方法
这里的电脑人机方法我们选择使用一种简单的方法,利用HashMap建立一个权值表,赋予不同棋盘情况不同的权值,然后让电脑选择在权值最大的地方下棋即可实现。
因为之前数组中我们将黑白棋分别赋值1,2,那么就可以根据此情况来设置权值表,可以如下图所示:
//创建权值表
hm.put("1", 10);
hm.put("11", 100);
hm.put("111", 5000);
hm.put("1111", 8000);
hm.put("12", 5);
hm.put("112", 80);
hm.put("1112", 3000);
hm.put("11112", 10000);
hm.put("21", 11);
hm.put("211", 110);
hm.put("2111", 1100);
hm.put("21111", 11000);
hm.put("2", 20);
hm.put("22", 200);
hm.put("222", 4500);
hm.put("2222", 10000);
hm.put("221", 100);
hm.put("2221", 3000);
hm.put("22221", 12000);
hm.put("122", 5);
hm.put("1222", 500);
hm.put("12222", 10000);
之后,就同样是遍历棋盘,找到每一个空位置,然后以这个空位置为起点,去看每个方向上棋盘的情况,然后设置一个ChessValue[][]数组来存储每一个空位置的最终各个方向上棋盘情况的权值总和,那么权值最大的地方,就是电脑需要下棋的地方。
在电脑下棋之后,同样要调用我们之前写过的判定胜负的方法来进行判定,确保电脑和玩家每下一次棋子就可以进行一次判定。
完整的电脑下棋AI方法的代码如下:
public void AI() {//人机对战,电脑怎么下棋判定
//创建权值表
hm.put("1", 10);
hm.put("11", 100);
hm.put("111", 5000);
hm.put("1111", 8000);
hm.put("12", 5);
hm.put("112", 80);
hm.put("1112", 3000);
hm.put("11112", 10000);
hm.put("21", 11);
hm.put("211", 110);
hm.put("2111", 1100);
hm.put("21111", 11000);
hm.put("2", 20);
hm.put("22", 200);
hm.put("222", 4500);
hm.put("2222", 10000);
hm.put("221", 100);
hm.put("2221", 3000);
hm.put("22221", 12000);
hm.put("122", 5);
hm.put("1222", 500);
hm.put("12222", 10000);
for(int i=0;i<ChessArray.length;i++) {
for(int j=0;j<ChessArray[i].length;j++) {
if(ChessArray[i][j]==0) {//判断是否有棋子
String code="";
int color=0;
for(int k=i+1;k<ChessArray.length;k++) {//向右开始时遍历
if(ChessArray[k][j]==0) {
break;
}else {
if(color==0) {
color=ChessArray[k][j];
code+=ChessArray[k][j];
}else if(color==ChessArray[k][j]) {
code+=ChessArray[k][j];
}else {
code+=ChessArray[k][j];
break;
}
}
}
Integer value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int k=i-1;k>0;k--) {//向左开始时遍历
if(ChessArray[k][j]==0) {
break;
}else {
if(color==0) {
color=ChessArray[k][j];
code+=ChessArray[k][j];
}else if(color==ChessArray[k][j]) {
code+=ChessArray[k][j];
}else {
code+=ChessArray[k][j];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int k=j-1;k>0;k--) {//向上开始时遍历
if(ChessArray[i][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[i][k];
code+=ChessArray[i][k];
}else if(color==ChessArray[i][k]) {
code+=ChessArray[i][k];
}else {
code+=ChessArray[i][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int k=j+1;k<ChessArray.length;k++) {//向下开始时遍历
if(ChessArray[i][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[i][k];
code+=ChessArray[i][k];
}else if(color==ChessArray[i][k]) {
code+=ChessArray[i][k];
}else {
code+=ChessArray[i][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int o=i-1,k=j-1;k>0&&o>0;k--,o--) {//向左上开始时遍历
if(ChessArray[o][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[o][k];
code+=ChessArray[o][k];
}else if(color==ChessArray[o][k]) {
code+=ChessArray[o][k];
}else {
code+=ChessArray[o][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int o=i+1,k=j-1;k>0&&o<ChessArray.length;k--,o++) {//向右上开始时遍历
if(ChessArray[o][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[o][k];
code+=ChessArray[o][k];
}else if(color==ChessArray[o][k]) {
code+=ChessArray[o][k];
}else {
code+=ChessArray[o][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int o=i+1,k=j+1;k<ChessArray.length&&o<ChessArray.length;k++,o++) {//向右下开始时遍历
if(ChessArray[o][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[o][k];
code+=ChessArray[o][k];
}else if(color==ChessArray[o][k]) {
code+=ChessArray[o][k];
}else {
code+=ChessArray[o][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int o=i-1,k=j+1;k<ChessArray.length&&o>0;k++,o--) {//向左下开始时遍历
if(ChessArray[o][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[o][k];
code+=ChessArray[o][k];
}else if(color==ChessArray[o][k]) {
code+=ChessArray[o][k];
}else {
code+=ChessArray[o][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
}
}
}
//找到ChessValue中的最大值点让电脑下棋
int max=0;
int goalx = 0,goaly = 0;
for(int i=0;i<ChessArray.length;i++) {
for(int j=0;j<ChessArray.length;j++) {
if(ChessValue[i][j]>max) {
max=ChessValue[i][j];
goalx=i;
goaly=j;
}
}
}
if(max !=0) {
gr.fillOval(goalx*20+50-10, goaly*20+50-10, 20, 20);
ChessArray[goalx][goaly]=2;
if(Win1(goalx,goaly)==5||Win2(goalx,goaly)==5||Win3(goalx,goaly)==5||Win4(goalx,goaly)==5) {//确定获胜标准
{ nb=0;
JOptionPane.showMessageDialog(null, "白棋胜利");
}
}
}
//清空权值
for(int i=0;i<ChessArray.length;i++) {
for(int j=0;j<ChessArray.length;j++) {
ChessValue[i][j]=0;
}
}
}
完整代码,以及悔棋、清空棋盘功能
这样基本就完成了一个简单的五子棋创作,当然其中还包含着一些悔棋功能,清空棋盘功能,这些功能也基本上都是利用重绘来实现的,具体的操作就不在讲述,完整代码中有写,自行理解即可。
整个五子棋分为三个大类,分别是窗体DrawUI类,监听器UIListener类,以及MyFrame类,每个类完整的代码如下所示:
DrawUI:
public class DrawUI
{
public static void main(String args[]) {
DrawUI drawui=new DrawUI();//设置对象
drawui.ShowUI();//让对象运行创建窗体的方法
}
public void ShowUI() {
MyFrame jf=new MyFrame();//创建窗体
jf.setSize(500,500);
jf.setLocationRelativeTo(null);
//设置窗体属性
jf.setTitle("五子棋");
jf.setResizable(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout fl=new FlowLayout();//设置窗体格式
jf.setLayout(fl);
JButton jb=new JButton("人人对战");//添加按钮
JButton jb1=new JButton("悔棋");
JButton jb2=new JButton("清空棋盘");
JButton jb3=new JButton("人机对战");
jf.add(jb);
jf.add(jb1);
jf.add(jb2);
jf.add(jb3);
jf.setVisible(true);
Graphics g=jf.getGraphics();//给窗体添加画笔
UIListener ul=new UIListener();
jb.addActionListener(ul);//给按钮添加监听器
jb1.addActionListener(ul);
jb2.addActionListener(ul);
jb3.addActionListener(ul);
jf.addMouseListener(ul);//给窗体添加监听器
ul.gr=g;//将画笔倒给UIlistener中的gr
// jf.ChessArray = ul.ChessArray;
jf.ul=ul;//为了在Myframe中使用ChessArray,将UIistener中的ul倒给Myframe中的ul
ul.jb11=jb;//将按钮jb倒给ul中的jb11,方便其使用jb
ul.mf=jf;//为了在UIlistener中重绘,将jf倒给其中的mf
}
}
UIListener:
public class UIListener implements MouseListener ,ActionListener{//监听器是接口
Graphics gr;
int[][] ChessArray=new int[22][22];
int[][] ChessValue=new int[22][22];
JButton jb11;
int nb=0;
int count=0;
int a,b,x,y,X,Y;
JFrame mf;
String zifu;
HashMap<String,Integer> hm=new HashMap<String,Integer>();
public void mouseClicked(MouseEvent e) {
// int a,b,x,y,X,Y;
int z=50,c=20;
Color c1=new Color(0,0,0);
Color c2=new Color(255,255,255);
a=e.getX();b=e.getY();//获得鼠标点击坐标
if(nb==1) {//确定是否可以下棋
if((a-z)%c>c/2) {//帮助x轴上点击点优化到坐标格子上
x=(a-z)/c+1;
}else {
x=(a-z)/c;
}
if((b-z)%c>c/2) {//帮助y轴上点击点优化到坐标格子上
y=(b-z)/c+1;
}else {
y=(b-z)/c;
}
if(ChessArray[x][y]==0) {//确保棋子只能下在没有棋子的地方
if(zifu.equals("人机对战")) {
gr.setColor(c1);
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=1;
gr.setColor(c2);
AI();
}else if(zifu.equals("人人对战")) {
if(count==0) {
gr.setColor(c1);
count++;
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=1;//黑子数组值为1,方便重绘使用
}else if(count==1) {
gr.setColor(c2);
count--;
gr.fillOval(x*c+z-10, y*c+z-10, 20, 20);
ChessArray[x][y]=2;//白子数组值为21,方便重绘使用
}
}
}else{
System.out.println("该位置已有棋子");
}
}else {
System.out.println("请选择对战类型");
}
if(Win1(x,y)==5||Win2(x,y)==5||Win3(x,y)==5||Win4(x,y)==5) {//确定获胜标准
if(ChessArray[x][y]==1) {
nb=0;
JOptionPane.showMessageDialog(null, "黑棋胜利");
}else if(ChessArray[x][y]==2) {
nb=0;
JOptionPane.showMessageDialog(null, "白棋胜利");
}
}
}
public void AI() {//人机对战,电脑怎么下棋判定
//创建权值表
hm.put("1", 10);
hm.put("11", 100);
hm.put("111", 5000);
hm.put("1111", 8000);
hm.put("12", 5);
hm.put("112", 80);
hm.put("1112", 3000);
hm.put("11112", 10000);
hm.put("21", 11);
hm.put("211", 110);
hm.put("2111", 1100);
hm.put("21111", 11000);
hm.put("2", 20);
hm.put("22", 200);
hm.put("222", 4500);
hm.put("2222", 10000);
hm.put("221", 100);
hm.put("2221", 3000);
hm.put("22221", 12000);
hm.put("122", 5);
hm.put("1222", 500);
hm.put("12222", 10000);
for(int i=0;i<ChessArray.length;i++) {
for(int j=0;j<ChessArray[i].length;j++) {
if(ChessArray[i][j]==0) {//判断是否有棋子
String code="";
int color=0;
for(int k=i+1;k<ChessArray.length;k++) {//向右开始时遍历
if(ChessArray[k][j]==0) {
break;
}else {
if(color==0) {
color=ChessArray[k][j];
code+=ChessArray[k][j];
}else if(color==ChessArray[k][j]) {
code+=ChessArray[k][j];
}else {
code+=ChessArray[k][j];
break;
}
}
}
Integer value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int k=i-1;k>0;k--) {//向左开始时遍历
if(ChessArray[k][j]==0) {
break;
}else {
if(color==0) {
color=ChessArray[k][j];
code+=ChessArray[k][j];
}else if(color==ChessArray[k][j]) {
code+=ChessArray[k][j];
}else {
code+=ChessArray[k][j];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int k=j-1;k>0;k--) {//向上开始时遍历
if(ChessArray[i][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[i][k];
code+=ChessArray[i][k];
}else if(color==ChessArray[i][k]) {
code+=ChessArray[i][k];
}else {
code+=ChessArray[i][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int k=j+1;k<ChessArray.length;k++) {//向下开始时遍历
if(ChessArray[i][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[i][k];
code+=ChessArray[i][k];
}else if(color==ChessArray[i][k]) {
code+=ChessArray[i][k];
}else {
code+=ChessArray[i][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int o=i-1,k=j-1;k>0&&o>0;k--,o--) {//向左上开始时遍历
if(ChessArray[o][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[o][k];
code+=ChessArray[o][k];
}else if(color==ChessArray[o][k]) {
code+=ChessArray[o][k];
}else {
code+=ChessArray[o][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int o=i+1,k=j-1;k>0&&o<ChessArray.length;k--,o++) {//向右上开始时遍历
if(ChessArray[o][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[o][k];
code+=ChessArray[o][k];
}else if(color==ChessArray[o][k]) {
code+=ChessArray[o][k];
}else {
code+=ChessArray[o][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int o=i+1,k=j+1;k<ChessArray.length&&o<ChessArray.length;k++,o++) {//向右下开始时遍历
if(ChessArray[o][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[o][k];
code+=ChessArray[o][k];
}else if(color==ChessArray[o][k]) {
code+=ChessArray[o][k];
}else {
code+=ChessArray[o][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
code="";
color=0;
value=null;
for(int o=i-1,k=j+1;k<ChessArray.length&&o>0;k++,o--) {//向左下开始时遍历
if(ChessArray[o][k]==0) {
break;
}else {
if(color==0) {
color=ChessArray[o][k];
code+=ChessArray[o][k];
}else if(color==ChessArray[o][k]) {
code+=ChessArray[o][k];
}else {
code+=ChessArray[o][k];
break;
}
}
}
value=hm.get(code);
if(value != null) {
ChessValue[i][j]+=value;
}
}
}
}
//找到ChessValue中的最大值点让电脑下棋
int max=0;
int goalx = 0,goaly = 0;
for(int i=0;i<ChessArray.length;i++) {
for(int j=0;j<ChessArray.length;j++) {
if(ChessValue[i][j]>max) {
max=ChessValue[i][j];
goalx=i;
goaly=j;
}
}
}
if(max !=0) {
gr.fillOval(goalx*20+50-10, goaly*20+50-10, 20, 20);
ChessArray[goalx][goaly]=2;
if(Win1(goalx,goaly)==5||Win2(goalx,goaly)==5||Win3(goalx,goaly)==5||Win4(goalx,goaly)==5) {//确定获胜标准
{ nb=0;
JOptionPane.showMessageDialog(null, "白棋胜利");
}
}
}
}
//清空权值
for(int i=0;i<ChessArray.length;i++) {
for(int j=0;j<ChessArray.length;j++) {
ChessValue[i][j]=0;
}
}
}
//判定获胜的方法
public int Win1(int xx,int yy) {//判定横向棋子是否有相连的
int count1=0;
for(int i=xx-1;i>=0;i--) {
if(ChessArray[i][yy]==ChessArray[xx][yy]) {
count1++;
}else break;
}
for(int j=xx;j<ChessArray.length;j++) {
if(ChessArray[j][yy]==ChessArray[xx][yy]) {
count1++;
}else break;
}
return count1;
}
public int Win2(int xx,int yy) {//判定纵向棋子是否有相连的
int count2=0;
for(int n=yy-1;n>=0;n--) {
if(ChessArray[xx][n]==ChessArray[xx][yy]) {
count2++;
}else break;
}
for(int m=yy;m<ChessArray.length;m++) {
if(ChessArray[xx][m]==ChessArray[xx][yy]) {
count2++;
}else break;
}
return count2;
}
public int Win3(int xx,int yy) {//判定左下右上棋子是否有相连的
int count3=0;
for(int o=xx-1,p=yy+1;o>=0&&p<ChessArray.length;o--,p++) {
if(ChessArray[o][p]==ChessArray[xx][yy]) {
count3++;
}else break;
}
for(int o=xx,p=yy;o<ChessArray.length&&p>=0;o++,p--) {
if(ChessArray[o][p]==ChessArray[xx][yy]) {
count3++;
}else break;
}
return count3;
}
public int Win4(int xx,int yy) {//判定左上右下棋子是否有相连的
int count4=0;
for(int o=xx-1,p=yy-1;o>=0&&p>=0;o--,p--) {
if(ChessArray[o][p]==ChessArray[xx][yy]) {
count4++;
}else break;
}
for(int o=xx,p=yy;o<ChessArray.length&&p<ChessArray.length;o++,p++) {
if(ChessArray[o][p]==ChessArray[xx][yy]) {
count4++;
}else break;
}
return count4;
}
public void Restart() {//重绘,删除之前的棋子,只保留棋盘
for(int i=0;i<ChessArray.length;i++) {
for(int j=0;j<ChessArray.length;j++) {
if(ChessArray[i][j]==1||ChessArray[i][j]==2) {
ChessArray[i][j]=0;
}
}
}
mf.repaint();
}
public void Hq() {//悔棋
ChessArray[x][y]=0;
mf.paint(gr);
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e){
}
public void mouseExited(MouseEvent e) {
}
public void actionPerformed(ActionEvent e) {//按钮监听器执行一些操作
if(jb11==e.getSource()) {
nb=1;
}
zifu=e.getActionCommand();
if(zifu.equals("清空棋盘")) {
Restart();
}
if(zifu.equals("悔棋")) {
Hq();
}
if(zifu.equals("人机对战")) {
nb=1;
}
}
}
MyFrame:
public class MyFrame extends JFrame{//MyFrame子类继承JFrame父类
public UIListener ul;
// int[][] ChessArray;
int z=50,c=20;
public void paint(Graphics g) {//重绘棋盘,确保刷新网页时候,棋盘还在
super.paint(g);
int x1,x2,y1,y2;
int X1,X2,Y1,Y2;
x1=50;x2=450;y1=70;y2=470;
X1=50;X2=450;Y1=70;Y2=470;
for(int i=0; i<21; i++) {
g.drawLine(x1,y1,x2,y1);
y1=y1+20;
}
for(int i=0; i<21; i++) {
g.drawLine(X1,Y1,X1,Y2);
X1=X1+20;
}
int[][] ChessArray = ul.ChessArray;
for(int i=0;i<ChessArray.length;i++) {//重绘棋子,网页刷新后,之前下过的棋子还在
for(int j=0;j<ChessArray.length;j++) {
if(ChessArray[i][j]==1) {
g.setColor(Color.black);
g.fillOval(i*c+z-10, j*c+z-10, 20, 20);
}
if(ChessArray[i][j]==2) {
g.setColor(Color.white);
g.fillOval(i*c+z-10, j*c+z-10, 20, 20);
}
}
}
}
}
收获理解
五子棋这个小项目,在最开始的写的时候会遇到各种各样的问题,但随着不断学习钻研,很多东西都可以慢慢去掌握,例如:如何重绘,如何找最大值,如何设置棋子,如何在不同的类中去调用其他类的方法或者属性。能让自己更好的理解类与对象,属性,变量等一些基础知识,