五子棋开发过程

1.五子棋功能

1.黑白轮流下棋 – 逻辑控制

2.下棋的范围 – 限制,棋子不能被覆盖

3.棋子最好下在网格中心

4.悔棋

5.悔棋双方计数功能

6.判断输赢

7.存读档

8.录制回放

9.AI下棋算法

2.项目开发流程

1.设计棋盘

1.棋盘画在窗体上,15*15网格,绘制直线画出。

2.SIZE:网格间距大小,Row,Column行列值,X,Y左上角的坐标。

3.拖动窗体不会消失,在重绘函数中画出(继承JFrame 重写paint方法,窗体的paint方法 – 在窗体改变大小初始化时自动调用刷新。

public void paint(Graphics g){   //重绘传递画笔参数,可用
        super.paint(g);  //注意 必须先调用父类绘制窗体
        //绘制图片
        g.drawImage(image, X, Y,COLUMN*SIZE, ROW*SIZE, null);
        this.setIconImage(new ImageIcon("Image//login.png").getImage());                         //给窗体加图标
        for(int i=0; i<=ROW; i++){
            g.drawLine(X+SIZE*i, Y, X+SIZE*i, Y+ROW*SIZE);
        }

        for(int i=0; i<=COLUMN; i++){     //重回功能里面写的函数,拖动窗体不会消失
            g.drawLine(X, Y+SIZE*i, X+COLUMN*SIZE, Y+SIZE*i);
        }

2.黑白轮流下棋

1.每次点击可以绘制一个实心的圆,g.fillOval();参数是圆的外切矩形的左上角 宽 高

–在窗体上添加鼠标监听器: 鼠标拖动移动监听器

    @Override
    public void mousePressed(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        if(x<X||x>X+COLUMN*SIZE||y<Y||y>Y+ROW*SIZE){   //限制下棋范围
            return;
        }
        ChessX = x;
        ChessY = y;
        ChessX = (ChessX-X+SIZE/2)/SIZE;         //找出该坐标位于第几格,为X轴坐标
        ChessY = (ChessY-Y+SIZE/2)/SIZE;

        if(chessrecord[ChessX][ChessY] != 0)   //当前棋盘位置有棋子,无法下棋
            return;



//        e.getClickCount();    获取鼠标点击次数
        if(flag == true) {                //设置boolean变量改变状态
            g.setColor(Color.BLACK);
            flag = false;
            countblack++;
            g.fillOval(ChessX*SIZE-SIZE/2+X, ChessY*SIZE-SIZE/2+Y, SIZE, SIZE);  //还原坐标
            chesscolor = 1;
            chessrecord[ChessX][ChessY] = chesscolor;   //棋盘棋子(X,Y)坐标缩小为格数

            //创建棋子对象,棋子对象坐标,个数,颜色,保存下来
            index++;           //-1++=0; 此时下标0中存棋子
            Chess chess = new Chess(index, chesscolor, ChessX, ChessY);
//            System.out.println("ChesX"+x1+"ChessY"+y1+"index"+index);
            chesssaving[index] = chess;  //将棋子对象存储到棋子保存数组中,index++

//            gobangjf.repaint();

        }
        else{
            g.setColor(Color.white);
            flag = true;
            countwhite++;
            g.fillOval(ChessX*SIZE-SIZE/2+X, ChessY*SIZE-SIZE/2+Y, SIZE, SIZE);  //还原坐标
            chesscolor = 2;
            chessrecord[ChessX][ChessY] = chesscolor;         //X轴坐标为棋盘列数,Y轴坐标为棋盘行数

//            gobangjf.repaint();

            //创建棋子对象,棋子对象坐标,个数,颜色,保存下来
            index++;
            Chess chess = new Chess(index, chesscolor, ChessX, ChessY);
            chesssaving[index] = chess;


        }

    }

3.重绘棋子

保证窗体大小改变时,棋子会消失,因此需要重绘棋子,我们需要保存棋子的数据 :行列值,只有黑白之分,存在矩阵中,依据棋盘格子交叉数生成一个二维数组。

int[][] chessrecord = new int[ROW+1][CLOUM +1];  //存储棋子
chesscolor 0:1:黑 2:白
// 初始化数组
int[][] chessrecord = new int[ROW+1][CLOUM +1];
// 每下一颗棋子 就存入
chesscolor = 1 或者 2
chessrecord[chessX][chessY]=chesscolor;

int[][] chessrecord = gl.getchessrecord();  //重绘棋子
//        System.out.println(chessrecord.toString());      非list接口定义的数组,无tostring功能
        for(int i=0; i<chessrecord.length; i++){      //棋盘记录数组行为X轴Y轴 行数,列为列数
            for(int j=0; j<chessrecord[i].length; j++){
                //X轴Y轴行列数转换为数组坐标,转置
//                System.out.print(chessrecord[j][i]+ " ");  //println每输出一次换一次行,打开UI即调用重绘函数
                if(chessrecord[i][j]==1){
                    g.setColor(Color.BLACK);
                    g.fillOval(i*SIZE-SIZE/2+X, j*SIZE-SIZE/2+Y, SIZE, SIZE);  //依据当前棋盘记录中的行列值重绘
                }
                else if(chessrecord[i][j]==2){
                    g.setColor(Color.WHITE);
                    g.fillOval(i*SIZE-SIZE/2+X, j*SIZE-SIZE/2+Y, SIZE, SIZE);
                }
            }
//            System.out.println();           //sout+Enter打印语句快捷键, println为换行语句

        }

4.悔棋

存储棋子为棋子对象: 可用于悔棋,存档和读档,根据棋子顺序来存储棋子对象形成一个顺序数组。

Chess[] chesssaving = new Chess[(ROW+1)*(COLUMN+1)];      //棋盘保存数组保存棋子

悔棋实现方法:
1.取出当前的栈顶(最后存入的这颗棋子) 棋子对象
2.根据棋子的行列值 去 到 chessrecord中删除
3.再将当前的棋子一维数组中棋子对象删除

 if(text.equals("悔棋")) {            //悔棋按钮必须传入窗体监听器
            //chesssaving下标首先为0
            if(index<0){           //下标小于0,返回
                return;
            }
                Chess curchess = chesssaving[index];  //取出最后一颗棋子对象,下标为index
                int curChessX = curchess.ChessX;
                int curChessY = curchess.ChessY;
                chessrecord[curChessX][curChessY] = 0;    //在棋盘记录数组中重绘棋子,当前位置棋子为空
                chesssaving[index] =null;   //删除棋盘保存数组悔棋对象
                index--;   //新数组棋子个数减1
                gobangjf.repaint();


        }

5.判断输赢

规则:在横向,纵向,左斜,右斜四个方向找到大于或等于同色五子连棋
实现方法:每次下棋从当前下的这个棋子向八个小方向遍历
横向(向左 与 向右)
纵向(向上 与 向下)
右斜(左下方(x-- y++) 与 右上方(x++ y–))
左斜 (右下方(x++ y++) 与 左上方(x-- y–))
统计4个大方向上的连子数,若存在连子数>=5的情况,则获胜,需要最新的二位数组,需要当前最后下的棋子的行列值。

 //判断输赢
            if(IsWin.IsWin(chessrecord, ChessX,ChessY))
            JOptionPane.showMessageDialog(null, "执白棋者获得胜利");
            if(IsWin.IsWin(chessrecord, ChessX,ChessY))
                JOptionPane.showMessageDialog(null, "执黑棋者获得胜利");
                此时坐标已经存入棋子记录数组
//判断此时棋子上下左右斜上斜下,此时X,Y每按下一次按钮改变一次,函数调用一次,但是数组是总体的数组

    public static boolean IsWin(int[][] chessrecord, int ChessX, int ChessY){   //静态函数可以用类名直接调用
        if(checkrow(chessrecord, ChessX, ChessY)>=5|| checkcolumn(chessrecord, ChessX, ChessY)>=5|| checkedgeleft(chessrecord, ChessX, ChessY)>=5||checkedgeright(chessrecord, ChessX, ChessY)>=5)
            return true;
        else
            return false;
    }

    
    public static int checkrow (int[][] chessrecord, int x, int y) {  //传入当前棋子坐标
        int count = 1;          //局部变量,不然一直加
        for (int i = x+1; i < ROW + 1; i++) {  //判断纵轴棋子下侧是否赢
            if (chessrecord[i][y] == chessrecord[x][y]) {
                count++;
            } else {
                break;         //无连续5个棋子,结束循环
            }
        }

        for (int i = x-1; i >= 0; i--) {  //判断纵轴棋子上侧是否赢
            if (chessrecord[i][y] == chessrecord[x][y]) {
                count++;
            } else {            //无5个连续的棋子,结束循环
                break;
            }
        }
        return count;
//            System.out.println("row"+count);       //多输出坐标判断个数
    }

    public static int checkcolumn(int[][] chessrecord, int x, int y){
        int count = 1;
        for(int j=y+1; j<COLUMN+1; j++) {  //判断横轴棋子右侧是否赢
            if (chessrecord[x][j] == chessrecord[x][y]) {
                count++;
            } else {
                break;
            }
        }

        for(int j=y-1; j>=0; j--) {  //判断横轴棋子左侧是否赢
            if (chessrecord[x][j] == chessrecord[x][y]) {
                count++;
            }
            else {
                break;
            }
        }
//         System.out.println("column"+count);         //多输出坐标判断个数
        return count;
    }

    public static int checkedgeleft(int[][] chessrecord, int x, int y){  //判断棋子左斜轴是否有连续5个棋子
        int count = 1;
        int i = x;
        int j = y;
        while (i<ROW && j<COLUMN) {
            if (chessrecord[i][j] == chessrecord[i+1][j+1]){
                count++;
                i++;
                j++;
            }
            else {
                break;
            }
        }
        i = x;
        j = y; //重置x,y坐标,判断下
        while(i>0 && j>0){
            if(chessrecord[i][j] == chessrecord[i-1][j-1]){
                count++;
                i--;
                j--;
            }
            else {
                break;
            }

        }
//            System.out.println("count"+count);         //输出连续棋子的个数
        return count;
    }


    public static int checkedgeright(int[][] chessrecord, int x, int y){  //判断棋子右斜轴是否有连续5个棋子
        int count = 1;
        int i = x;
        int j = y;
        while (i>0 && j<COLUMN) {
            if (chessrecord[i][j] == chessrecord[i-1][j+1]){
                count++;
                i--;
                j++;
            }
            else {
                break;
            }

        }
        i = x;
        j = y;
        while(i<ROW && j>0){
            if(chessrecord[i][j] == chessrecord[i+1][j-1]){
                count++;
                i++;
                j--;
            }
            else {
                break;
            }

        }
//        System.out.println("右"+count);     //输出右斜轴个数
//        if (count >= 5) {
//            if (chessrecord[x][y] == 1) {
//                JOptionPane.showMessageDialog(null, "执黑棋者获得胜利");
//            } else if (chessrecord[x][y] == 2) {
//                JOptionPane.showMessageDialog(null, "执白棋者获得胜利");
//            }
        return count;
    }
}

6.人机对战

package com.zq0805;

import java.util.HashMap;


public class hashmap {
    HashMap<String, Integer> hash = new HashMap<>();    //创建hashmap对象,记录连子情况和得分

    public hashmap(){
        //        两端通畅为活连;
//      hash = hashmap;              //将hashmap地址赋给hash
        hash.put("010", 10);    //黑棋活一连 10分  这个位置10分 黑棋下或者白棋下都好
        hash.put("0110", 50);   //活二连 50分
        hash.put("01110", 500); //活三连 500分
        hash.put("011110", 2000);  //活四连 2000分
        hash.put("020", 10);   //白棋活一连 10分
        hash.put("0220", 50);  //白棋活二连 50分
        hash.put("02220", 500); //白棋活三连 500分
        hash.put("022220", 2000);  //白棋活四连 2000分
        // 一端通畅为死连
        //黑棋死一连5分
        hash.put("01", 5);
        hash.put("012", 5);
        //黑棋死二连25分
        hash.put("011", 25);
        hash.put("0112", 25);
        //黑棋死三连250分
        hash.put("0111", 250);
        hash.put("01112", 250);
        //黑棋死四连1000分
        hash.put("01111", 1000);
        hash.put("011112", 1000);

        //白棋死一连5分
        hash.put("02", 5);
        hash.put("021", 5);
        //白棋死二连25分
        hash.put("022", 25);
        hash.put("0221", 25);
        //白棋死三连250分
        hash.put("0222", 250);
        hash.put("02221", 250);
        //白棋死四连1000分
        hash.put("02222", 1000);
        hash.put("022221", 1000);
//      System.out.println("hash.get(0222)"+hash.get("0222"));
    }
}




package com.zq0805;

public class HashMapChess implements GoBangConfig{
    static int[][] chessweight = new int[ROW+1][COLUMN+1];
    static hashmap Hashmap = new hashmap();

    //测试数据
//    static int[][] test = {{0, 0, 1, 2, 0},
//                           {1, 2, 2, 1, 0},
//                           {2, 1, 0, 0 ,1},
//                           {1, 2, 0, 0, 1},
//                           {2, 2, 1, 0, 0}};


    public static int[][] intelligence(int[][] chessrecord) {  //主函数中变量为静态变量
        //从棋盘记录数组左上角开始遍历找到权值最大的位置下棋
        for (int i = 0; i < chessrecord.length; i++) {
            for (int j = 0; j < chessrecord[i].length; j++) {
//                System.out.print(chessrecord[i][j]+" ");
                int weight = 0;
                if (chessrecord[i][j] == 0) {   //表示当前位置无棋子,可以统计,从当前位置往右统计
                    int chessnum = chessrecord[i][j];  //记录当前棋子

                    //向右遍历找棋子
                    if (j < chessrecord[i].length - 1 && chessnum != chessrecord[i][j + 1]) {   //确保当前空位置右边有棋子,缺陷
                        int chess0 = chessrecord[i][j + 1];   //记录当前空位置右边棋子
                        String codeStr = "0";
                        for (int k = j + 1; k < chessrecord[i].length; k++) {
                            if (chessrecord[i][k] == chess0) {
                                codeStr = codeStr + chessrecord[i][k];  //字符串能直接为 字符串+数字
                            }
                            else {
                                codeStr = codeStr + chessrecord[i][k];
                                break;
                            }
                        }

//                        System.out.println(i+" "+j+"codeStr右"+codeStr);
                        if(Hashmap.hash.containsKey(codeStr)) {
                            weight += Hashmap.hash.get(codeStr);
                        }
                    }

                    //向左遍历找棋子
                    if (j > 0 && chessnum != chessrecord[i][j - 1]) {   //确保当前空位置左边有棋子,缺陷
                        int chess0 = chessrecord[i][j - 1];   //记录当前空位置左边棋子
                        String codeStr = "0";
                        for (int k = j - 1; k >= 0; k--) {
                            if (chessrecord[i][k] == chess0) {
                                codeStr = codeStr + chessrecord[i][k];  //字符串能直接为 字符串+数字
                            } else {
                                codeStr = codeStr + chessrecord[i][k];   //codeStr添加遍历到的不等于左边的棋子,为0或2
                                break;
                            }
                        }
//                        System.out.println(i+" "+j+"codeStr左"+codeStr);
                        if (Hashmap.hash.containsKey(codeStr)) {
                            weight += Hashmap.hash.get(codeStr);
                        }
                    }


                    //向上遍历找棋子
                    if (i > 0 && chessnum != chessrecord[i - 1][j]) {   //确保当前空位置上边有棋子,缺陷
                        int chess0 = chessrecord[i - 1][j];   //记录当前空位置上边棋子
                        String codeStr = "0";
                        for (int k = i - 1; k >= 0; k--) {
                            if (chessrecord[k][j] == chess0) {
                                codeStr = codeStr + chessrecord[k][j];  //字符串能直接为 字符串+数字
                            } else {
                                codeStr = codeStr + chessrecord[k][j];
                                break;
                            }
                        }
//                        System.out.println(i+" "+j+"codeStr上"+codeStr);
                        if (Hashmap.hash.containsKey(codeStr)) {
                            weight += Hashmap.hash.get(codeStr);
                        }

                    }


                    //向下遍历找棋子
                    if (i < chessrecord.length - 1 && chessnum != chessrecord[i + 1][j]) {   //确保当前空位置上边有棋子,缺陷
                        int chess0 = chessrecord[i + 1][j];   //记录当前空位置上边棋子
                        String codeStr = "0";
                        for (int k = i + 1; k < chessrecord.length; k++) {
                            if (chessrecord[k][j] == chess0) {
                                codeStr = codeStr + chessrecord[k][j];  //字符串能直接为 字符串+数字
                            } else {
                                codeStr = codeStr + chessrecord[k][j];
                                break;
                            }
                        }
//                        System.out.println(i+" "+j+"codeStr下"+codeStr);
                        if (Hashmap.hash.containsKey(codeStr)) {
                            weight += Hashmap.hash.get(codeStr);
                        }
                    }
                    //向左上遍历找棋子
                    if (i > 0 && j >0 && chessnum != chessrecord[i - 1][j-1]) {  //确保当前空位置左上有棋子,缺陷
                        int chess0 = chessrecord[i - 1][j-1];      //记录当前空位置左上边棋子
                        String codeStr = "0";
                        for (int m = i - 1, n = j-1; m >= 0 && n >=0; m--, n--) {      //for循环定义两个参数
                            if (chessrecord[m][n] == chess0) {
                                codeStr = codeStr + chessrecord[m][n];  //字符串能直接为 字符串+数字
                            } else {
                                codeStr = codeStr + chessrecord[m][n];
                                break;
                            }
                        }
//                        System.out.println(i+" "+j+"codeStr上"+codeStr);
                        if (Hashmap.hash.containsKey(codeStr)) {
                            weight += Hashmap.hash.get(codeStr);
                        }
                    }
                    //向右上遍历棋子
                    if (i > 0 && j < chessrecord[i].length - 1 && chessnum != chessrecord[i - 1][j + 1]) {  //确保当前空位置左上有棋子,缺陷
                        int chess0 = chessrecord[i - 1][j+1];      //记录当前空位置左上边棋子
                        String codeStr = "0";
                        for (int m = i - 1, n = j + 1; m >= 0 && n < chessrecord[i].length; m--, n++) {      //for循环定义两个参数
                            if (chessrecord[m][n] == chess0) {
                                codeStr = codeStr + chessrecord[m][n];  //字符串能直接为 字符串+数字
                            } else {
                                codeStr = codeStr + chessrecord[m][n];
                                break;
                            }
                        }
//                        System.out.println(i+" "+j+"codeStr上"+codeStr);
                        if (Hashmap.hash.containsKey(codeStr)) {
                            weight += Hashmap.hash.get(codeStr);
                        }
                    }

                    //向左下遍历棋子
                    if (i < chessrecord.length - 1 && j > 0 && chessnum != chessrecord[i + 1][j-1]) {  //确保当前空位置左上有棋子,缺陷
                        int chess0 = chessrecord[i + 1][j-1];      //记录当前空位置左上边棋子
                        String codeStr = "0";
                        for (int m = i + 1, n = j-1; m <chessrecord.length && n >=0; m++, n--) {      //for循环定义两个参数
                            if (chessrecord[m][n] == chess0) {
                                codeStr = codeStr + chessrecord[m][n];  //字符串能直接为 字符串+数字
                            } else {
                                codeStr = codeStr + chessrecord[m][n];
                                break;
                            }
                        }
//                        System.out.println(i+" "+j+"codeStr上"+codeStr);
                        if (Hashmap.hash.containsKey(codeStr)) {
                            weight += Hashmap.hash.get(codeStr);
                        }
                    }

                    //向右下遍历棋子
                    if (i < chessrecord.length-1 && j <chessrecord[i].length-1 && chessnum != chessrecord[i + 1][j + 1]) {  //确保当前空位置左上有棋子,缺陷
                        int chess0 = chessrecord[i + 1][j+1];      //记录当前空位置右下边棋子
                        String codeStr = "0";
                        for (int m = i + 1, n = j + 1; m < chessrecord.length && n < chessrecord[i].length; m++, n++) {      //for循环定义两个参数
                            if (chessrecord[m][n] == chess0) {
                                codeStr = codeStr + chessrecord[m][n];  //字符串能直接为 字符串+数字
                            } else {
                                codeStr = codeStr + chessrecord[m][n];
                                break;
                            }
                        }
//                        System.out.println(i+" "+j+"codeStr上"+codeStr);
                        if (Hashmap.hash.containsKey(codeStr)) {
                            weight += Hashmap.hash.get(codeStr);
                        }
                    }

                }
                chessweight[i][j] = weight;
//                System.out.print("weight"+weight+"");   //+空格
            }
//            System.out.println();
        }
        return chessweight;
    }
}

7.存读档

if(text.equals("存档")) {  //将当前所有棋子保存下来,已经有两个数组,一个保存坐标数组,绘制棋子,一个保存棋子对象,有坐标
            int count = 0;   //记录当前棋谱的棋子个数
            for (int i = 0; i < chessrecord.length; i++) {   //数组不能直接复制,不然传地址
                for (int j = 0; j < chessrecord[i].length; j++) {
                    chessstorage[i][j] = chessrecord[i][j];
                    if(chessrecord[i][j] != 0){
                        count++;        //所有棋子的个数
                    }
                }
            }
            //存档不需要改变index,此时index = count-1
            for(int k=0; k<=count-1; k++){
                chesssave[k] = chesssaving[k];       //不可 chesssave指向chesssaving地址
            }
        }
        if(text.equals("读档")){
            int count = 0;
            for (int i = 0; i < chessstorage.length; i++) {   //数组不能直接复制,不然传地址
                for (int j = 0; j < chessstorage[i].length; j++) {
                    chessrecord[i][j] = chessstorage[i][j];
                    if(chessrecord[i][j] != 0){
                        count++;          //棋子保存数组中棋子的个数,此时要改变棋子保存数组的索引
                    }
                }
                for(int k=0; k<chesssaving.length; k++){
                    chesssaving[k] = chesssave[k];       //不可 chesssave指向chesssaving地址
                }
                //读档后要改变

            }
            index = count-1;  //当前棋子个数下标为棋子个数减一
            gobangjf.repaint();

        }

8.录制回放

private static final Image image1 = new ImageIcon("D:\\IDEA 2019\\test\\Image\\chess111.jpg").getImage();  //Iamge接口
    private static final Image image2 = new ImageIcon("D:\\IDEA 2019\\test\\Image\\222.jpeg").getImage();

    public void paint() {   //重绘传递画笔参数,可用
        //绘制图片
        g.drawImage(image2, 0, 0, 1000,1000,null);
        g.drawImage(image1, X, Y,COLUMN*SIZE, ROW*SIZE, null);
        g.setColor(Color.BLACK);
        for (int i = 0; i <= ROW; i++) {
            g.drawLine(X + SIZE * i, Y, X + SIZE * i, Y + ROW * SIZE);
        }

        //重绘按钮
        for (int i = 0; i <= COLUMN; i++) {     //重回功能里面写的函数,拖动窗体不会消失
            g.drawLine(X, Y + SIZE * i, X + COLUMN * SIZE, Y + SIZE * i);
        }
        for (int k = 0; k <= index; k++){
            int i = chesssaving[k].ChessX;
            int j = chesssaving[k].ChessY;
            if(chesssaving[k].chesscolor == 1) {
                g.setColor(Color.BLACK);
                g.fillOval(i * SIZE - SIZE / 2 + X, j * SIZE - SIZE / 2 + Y, SIZE, SIZE);
            } else if (chesssaving[k].chesscolor == 2) {
                g.setColor(Color.WHITE);
                g.fillOval(i * SIZE - SIZE / 2 + X, j * SIZE - SIZE / 2 + Y, SIZE, SIZE);
            }
            //代码延时
            try {
                Thread.sleep(500);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            //录制回放结束后,刷新窗体,绘制的图片消失
        }

    }


   if(text.equals("回放")){
            //在图片上重新画棋盘,不需要初始化数组

            //repaint函数在线程最后调用
            paint();
    }
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值