JAVA实现基础版五子棋

一.基本步骤

1.画出棋盘

2.可以交替画出黑白棋子

3.保证棋子画在棋盘交点处

4.添加开始与结束按钮

5.实现悔棋

6.判断输赢

7.AI下棋(做一个自己下不过的AI超酷的!!)

二.个人优化

1.棋子3D化

2.闪屏问题的处理

三.问题解决

1.this究竟是个什么?

2.super.paint(g);能咋?

3.HashMap是什么?

四.具体代码实现

1.画棋盘

1)弄一个窗体

public class Gov0 extends JFrame implements Data{
    public void getBoard(){
        //this 在这里指的是在主方法里创建的对象
        //接着利用JFrame中的paint给棋盘画线
        //如果新建一个JFrame的对象则画线画不上
        JFrame jf=this;
        jf.setSize(900,900);
        jf.setTitle("五子棋v0");
        jf.setDefaultCloseOperation(EXIT_ON_CLOSE);
        jf.setVisible(true);
    }

this是什么?

this指当前调用方法的对象

在该类中,this均指调用getBoard这个对象

 public static void main(String[]args){
        new Gov0().getBoard();
    }

在重写JFrame的paint方法时,先创建一个Data接口,把要用的数据写进去,以便于多个类可以重复使用

public interface Data {
    public static int SIZE=40;
    public static int x0=50;
    public static int y0=50;
    public static int COLUMN=15;
    public static int ROW=15;
}

2)在窗体上画线

public void paint(Graphics g) {
        
        for(int i=0;i<=ROW;i++){
            g.drawLine(x0,y0+SIZE*i,x0+COLUMN*SIZE,y0+SIZE*i);
            g.drawLine(x0+SIZE*i,y0,x0+SIZE*i,y0+SIZE*ROW);
        }

//不需要在主方法中用对象调用paint方法
    }

2.画出棋子

1)画出黑白交替的实心圆

int flag=1;
    public void mousePressed(MouseEvent e) {
        int x=e.getX();
        int y=e.getY();
        if(flag==1){
            g.setColor(Color.black);
            g.fillOval(x-SIZE/2,y-SIZE/2,SIZE,SIZE);
        flag=2;
        }
        else if(flag==2){
            g.setColor(Color.WHITE);
            g.fillOval(x-SIZE/2,y-SIZE/2,SIZE,SIZE);
            flag=1;
        }

怎么实现画出3D的棋子呢?

  if(flag==1){
            for(int i=20;i>=0;i--) {
                Color color=new Color(120-6*i,120-6*i,120-6*i);
                g.setColor(color);
                g.fillOval(x-i,y-i,2*i,2*i);
            }
        flag=2;
        }
  else if(flag==2){
            for(int i=0;i<=20;i++) {
                Color color = new Color(135+6*i,135+6*i,135+6*i);
                g.setColor(color);
                g.fillOval(x-20+i,y-20+i,40-2*i,40-2*i);
            }
            flag=1;
        }

利用循环创造颜色的渐变,需要注意的是

1>在画圆的时候要保证先画大圆再画小圆

2>黑棋两边黑中间灰形成3D,白棋两边灰中间白形成3D

总结来说,两边颜色深,中间颜色浅形成3D

3>为保证鼠标位于圆的中心,需要利用x0=x-width/2

3.保证棋子画在棋盘交点处

1)将坐标换算为新的棋盘

        int c=(x-x0+SIZE/2)/SIZE;
        int r=(y-y0+SIZE/2)/SIZE;
        int nx=x0+c*SIZE;
        int ny=y0+r*SIZE;
        if(flag==1){
            for(int i=20;i>=0;i--) {
                Color color=new Color(120-6*i,120-6*i,120-6*i);
                g.setColor(color);
                g.fillOval(nx-i,ny-i,2*i,2*i);
            }
        flag=2;
        }

2)处理一些细节问题

1>棋子越界问题

2>重复下棋问题

if(x>670||x<30||y<30||y>670){
            JOptionPane.showMessageDialog(null,"此处不可下棋!!");
            return;
        }
if(chessArr[r][c]!=0){
            JOptionPane.showMessageDialog(null,"此处不可以下棋!!");
            return;
        }

4.实现开始与结束游戏

public void actionPerformed(ActionEvent e) {
        String btnstr=e.getActionCommand();
        JButton btn=(JButton) e.getSource();
        if(btnstr.equals("开始游戏")){
            //开始游戏时把上一局的棋子清理掉
         
             ui0.repaint();
            //刷新即可清屏

            flag=1;

            btn.setText("结束游戏");

        }
        else if(btnstr.equals("结束游戏")){
            flag=0;
            btn.setText("开始游戏");
        }

    }

怎么解决闪屏问题?

闪屏的出现是因为什么嘞?

与上一个项目中绘制图片缓慢的原因相似

棋盘上的线和之后加入悔棋之后需要绘制的棋子都是一个一个画的,太慢了,就出现了闪屏

那要怎么解决嘞?

也与上一个项目解决方案类似

我们需要先画好一张需要呈现的棋盘的样子,然后一次性画出来

      BufferedImage buffimg=new BufferedImage(700,700,BufferedImage.TYPE_INT_ARGB);
      Graphics g1=buffimg.createGraphics();
        //buffimg自己创造出一个画笔画在自己的画布上
        //g再画出buffimg即可

        //给棋盘划线
        for(int i=0;i<=ROW;i++){
            g1.drawLine(x0,y0+SIZE*i,x0+COLUMN*SIZE,y0+SIZE*i);
            g1.drawLine(x0+SIZE*i,y0,x0+SIZE*i,y0+SIZE*ROW);
        }
        
    g.drawImage(buffimg,0,0,null);

当解决了闪屏问题之后,会发现清屏不只是repaint那么简单了

super.paint(g);能咋?

在解决闪屏问题时去掉了super.paint(g);

super.paint(g);可以让微小的组件如开始游戏按钮一起刷新

不是组件的东西如画出的棋子会因为刷新而全部消失

而去掉super.paint(g);之后

1)新画出来的图片只新画了棋盘,棋子并没有消失

2)按钮不加repaint就不能在开始游戏与结束游戏之间切换了

        g1.setColor(Color.orange);
        g1.fillRect(0,0,700,700);

其实是因为必须要画一个有颜色的棋盘才可以把棋子盖上

5.实现悔棋

首先要找到最后一枚棋子

则需要对下的每一枚棋子进行储存

在实现悔棋时需要知道最后一枚棋子的行和列

在重新下棋时需要知道悔掉的棋子是黑棋还是白棋

创建一个Chess类,以实现用数组的形式存储棋子的数据

public class Chess {
    int flag;
    int r;
    int c;

    public Chess(int flag, int r, int c) {
        this.flag = flag;
        this.r = r;
        this.c = c;
    }

在下棋的位置记录棋子

                count++;
                Chess chess=new Chess(flag,r,c);
                chesslist[count-1]=chess;
else if(btnstr.equals("悔棋")){
            if(chessnum==0){
                JOptionPane.showMessageDialog(null,"没有棋子!!");
                return;
            }
            Chess chess=chesslist[chessnum-1];
          chessArr [chess.r][chess.c]=0;
          flag=chesslist[chessnum-1].flag;
          //得到下一次下棋时flag的值
          //清理这枚棋子的数据
          chesslist[chessnum-1]  =null;
          chessnum--;
          System.out.println("count0="+chessnum);
          //最后刷新
            ui0.repaint();

        }

千万要注意

1)获取最后一枚棋子的数据以及删除最后一枚棋子的数据的顺序

2)在记录棋子时count++的位置(不能加在循环内!!)

6.判断输赢

在行方向上计算连续棋子的个数

 public static int row(int [][]chessArr,int r,int c){
        //向右找棋子个数
        int num=chessArr[r][c];
        for(int i=c+1;i<chessArr[0].length;i++){
            if(chessArr[r][i]!=num){
                break;
            }
            else{
                count++;
            }
        }
        //System.out.println("向右"+count+"枚棋子");
        //向左找棋子个数
        
        for(int i=c-1;i>=0;i--){
            if(chessArr[r][i]!=num){
                break;
            }
            else{
                count++;
            }

        }
        
        count++;
        System.out.println("行方向上连续有"+count+"枚棋子");
        return count;
    }

列方向上的类似

在左上到右下的方向上计算连续棋子的个数

 public static int leftUpToRightDown(int [][]chessArr,int r,int c){
        //右下找棋子个数
        count=0;
        int num=chessArr[r][c];
        for(int i=1;i<Math.min((chessArr.length-r),(chessArr.length-c));i++){
            if(chessArr[r+i][c+i]!=num){
                break;
            }
            else{
                count++;
            }
        }
        System.out.println("向右下"+count+"枚棋子");
        //向左上找棋子个数

        for(int i=1;i<=Math.min(r,c);i++){
            if(chessArr[r-i][c-i]!=num){
                break;
            }
            else{
                count++;
            }

        }

        count++;
        System.out.println("左上到右下方向上连续有"+count+"枚棋子");
        return count;
    }

当棋子连成5个之后,判断输赢

public static boolean isWin(int [][]chessboard,int r,int c){
        if(row(chessboard,r,c)==5||
        column(chessboard,r,c)==5||
        leftUpToRightDown(chessboard,r,c)==5||
        rightUpToLeftDown(chessboard,r,c)==5        
        ){
            return true;
        }
        
    return false;    
    }

把写好的判断输赢加在下完棋的位置上

if(Win.isWin(chessArr,r,c)){
             if(flag==1){
                 JOptionPane.showMessageDialog(null,"白棋胜利!!");
                 flag=0;
             }
             else if(flag==2){
                 JOptionPane.showMessageDialog(null,"黑棋胜利!!");
             }
         }

7.AI下棋

1)先用HashMap把连子情况与对应的得分给存起来

 static HashMap<String,Integer> codemap=new HashMap<>();
   static {
        codemap.put("010",10);
        codemap.put("0110",50);
        codemap.put("01110",500);
        codemap.put("011110",5000);
        codemap.put("020",10);
        codemap.put("0220",50);
        codemap.put("02220",500);
        codemap.put("022220",5000);
        codemap.put("01",8);
        codemap.put("011",40);
        codemap.put("0111",400);
        codemap.put("01111",5000);
        codemap.put("02",8);
        codemap.put("022",40);
        codemap.put("0222",400);
        codemap.put("02222",5000);

    }

2)把各个方向连子情况的得分分别计算出来(以右边为例)

public static int right(int r,int c,int[][]chessArr){
        //右边第一颗棋子
        if(c+1>=chessArr.length){
            return 0;
        }
        //为边界
        else if(chessArr[r][c+1]==0){
            return 0;
        }
        //为0
        int r1=chessArr[r][c+1];
        //记录下右边第一颗棋子是1还是2
        String codestr="0"+r1;
        for(int i=c+2;i<chessArr.length;i++){
            //判断并记录右边第2,3,4,,,,颗棋子
            if(chessArr[r][i]==0){
                codestr+=0;
                break;
            }
            else if(chessArr[r][i]!=0){
                if(chessArr[r][i]==r1){
                    codestr+=r1;
                }
                else {
                    break;
                }

            }
        }
        System.out.println("连子情况为"+codestr);
        int wnum=codemap.get(codestr);
        System.out.println("得分为"+wnum);
        if(wnum==0){
            return 0;
        }
        return wnum;
    }

3)写一个判断AI应该下棋在什么位置的方法

public int [] getMax(int [][]chessboard){
        int [][]codeArr=new int[chessboard.length][chessboard[0].length];
        for(int i=0;i<chessboard.length;i++){
            for(int j=0;j<chessboard.length;j++){
                //是0的位置计算下此处的分数
                int num=chessboard[i][j];
                if(num==0){
                    int score=0;
                    score+=right(i,j,chessboard);
                    score+=left(i,j,chessboard);
                    score+=up(i,j,chessboard);
                    score+=down(i,j,chessboard);
                    score+=leftup(i,j,chessboard);
                    score+=rightdown(i,j,chessboard);
                    score+=rightup(i,j,chessboard);
                    score+=leftdown(i,j,chessboard);
                    codeArr[i][j]=score;
                }
                
            }
        }
        int max=0;
        int r=0,c=0;
        for(int i=0;i<chessboard.length;i++){
            for (int j=0;j<chessboard.length;j++){
                if(codeArr[i][j]>max){
                    max=codeArr[i][j];
                     x=i;
                     y=j;
                }
            }
        }
        return new int{r,c} ;
    }

4)把AI下棋与按钮监听结合

      else if(AI==1){
            if(flag==1){

                //下棋
                for(int i=20;i>=0;i--) {
                    Color color = new Color(120 - 6 * i, 120 - 6 * i, 120 - 6 * i);
                    g.setColor(color);
                    g.fillOval(nx - i, ny - i, 2 * i, 2 * i);
                }
                //把棋子存入chessArr
                chessArr[r][c]=1;
                //判断输赢
                if(Win.isWin(chessArr,r,c)){
                    JOptionPane.showMessageDialog(null,"玩家胜利!!");
                    return;
                }
                flag=2;
                //AI下棋
                int []location=AIgo.getMax(chessArr);
                int nr=location[0];
                int nc=location[1];
                System.out.println("nc:"+nc+"nr:"+nr);
                for(int i=0;i<=20;i++) {
                    Color color = new Color(135 + 6 * i, 135 + 6 * i, 135 + 6 * i);
                    g.setColor(color);
                    int nx1=x0+nc*SIZE;
                    int ny1=y0+nr*SIZE;
                    g.fillOval(nx1 - 20 + i, ny1 - 20 + i, 40 - 2 * i, 40 - 2 * i);
                }
                chessArr[nr][nc]=2;
                if(Win.isWin(chessArr,nr,nc)){
                    JOptionPane.showMessageDialog(null,"AI胜利!!");
                    return;
                }

                flag=1;


                }


        }

5)实现AI悔棋

else if(AI==1){
                Chess chess1 =chesslist[chessnum-1];
                System.out.println("chessnum="+chessnum);
                chessArr[chess1.r][chess1.c]=0;
                System.out.println("r="+chess1.r+"c="+chess1.c);
                System.out.println(chessArr[chess1.r][chess1.c]);
                flag=chess1.flag;
                chesslist[chessnum-1]=null;
                chessnum--;
                System.out.println("chessnum="+chessnum);
                Chess chess2=chesslist[chessnum-1];

                chessArr[chess2.r][chess2.c]=0;
                System.out.println("r="+chess2.r+"c="+chess2.c);
                System.out.println(chessArr[chess2.r][chess2.c]);
                //System.out.println("归0");
                flag=chess2.flag;
                chesslist[chessnum-1]=null;
                chessnum--;
                ui0.repaint();

            }

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值