n皇后问题实现GUI界面(java)

将n皇后问题可视化实现输出:
1、准备工作:
①新建一个长度为n x n的二维数组arr,n表示的是皇后的个数,表示皇后所放的位置。二维数组的值为0,表示这个位置并没有放置皇后,反之,如果值为1,表示已经放置了皇后。这个二维数组和按钮是对应的

新建窗口JFrame,然后进行设置其相关的参数,比如窗口可见setVisible,窗口的大小setSize(),setBounds()等。
③新建一个n x n二维数组来表示按钮,从而当对按钮进行点击的时候,就可以监听,跳出皇后。
为了更好的表示页面,那么通过循环嵌套,对按钮的背景进行更改,使其像棋盘一样,设置好之后,将按钮添加到窗口中。
在这里插入图片描述

代码实现如下:

   public static void paintChess(){
        int i ,j;
        for(i = 0; i<n; i++){
            for(j = 0; j<n;j++){
                button[i][j] = new JButton();//为每一个按钮开辟空间,从而方便下面的操作
                button[i][j].setOpaque(true);//设置控件是否透明,如果是true,那么表示控件不透明,反之表示透明
                if((i+j)%2==0)
                    button[i][j].setBackground(Color.BLACK);//将背景设成黑色
                else
                    button[i][j].setBackground(Color.WHITE);//背景设成白色
                frame.add(button[i][j]);//将按钮添加到窗口中
            }
        }
        frame.setVisible(true);//设置可见
        frame.setTitle("n皇后问题");//窗口的名字
        frame.setLayout(new GridLayout(n,n));//窗口的布局
        frame.setBounds(200,200,500,500);//前两个参数就相当于屏幕坐标的x,y轴,用来定位控件在屏幕中的位置,而后两个参数则是定义控件的大小
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//退出窗口
    }

④一张皇后棋子的照片

public static ImageIcon imageIcon = new ImageIcon("G:\\百度网盘\\学习路线\\捕获.PNG");//将图片添加到ImagIcon这个控件中,注意后面的是你的图片的存放路径

3、新建一个变量,表示已经输入多少个皇后了,每点击一次,都要进行比较,判断是否含有任意两个皇后是否在同一行、同一列、同一斜线上,如果含有,那么就将跳出窗口,同时输出失败了,否则,一直摆放皇后,直到摆放好n个皇后,然后再进行判断,如果含有任意两个皇后是否在同一行、同一列、同一斜线上,那么就将跳出窗口,同时输出失败了,否则输出。WONDERFUL。
例如:
在这里插入图片描述
判断是否在同一行、同一列、同一斜线上时思路:除了不需要遍历当前皇后的位置之外,其他位置必须要遍历,判断这些位置是否已经摆放了皇后,所以必须从0开始遍历到最后,否则就会错误。因为这里是随机点按钮的

这个和我之前写的判断是否相同有所不同,之前做的并没有时随机摆放皇后,所以只需要那当前的皇后和之前的皇后比较即可,做个标记,这里给出链接:https://blog.csdn.net/weixin_46544385/article/details/107436274
如果有更好的判断方法,请大家指教。

判断是否含有任意两个皇后在同一行、同一列、同一斜线上的代码:

public boolean check(int x,int y){
                        //判断任意两个皇后是否在同一列
                        for(int i = 0; i <n;i++){
                            if(i != x && arr[i][y] == 1)//除去当前位置的皇后x,如果是同一列,那么就返回false,表示摆放错误
                                return false;
                        }
                        //判断任意两个皇后是否在同一行
                        for(int i = 0; i <n; i++){
                            if(i != y && arr[x][i] == 1)//除去当前位置的皇后y,如果是在同一行,那么就返回false,表示摆放错误
                                return false;
                        }
                        //判断任意两个皇后是否在同一斜线,如果在,那么就返回false,表示摆放错误
                        for(int i = 0; i<n; i++){
                            for(int j = 0; j<n; j++){
                                if(i == x)//如果遍历到的皇后是当前的皇后,那么跳过这个皇后,判断其后面是否有皇后和他在同一斜线上
                                    break;
                                //如果不是当前的皇后x,那么开始判断是否含有任意两个皇后在同一斜线上,如果有那么就返回false,表示摆放错误
                                else if(arr[i][j] == 1 && Math.abs(i - x) == Math.abs(j - y))
                                    return false;
                            }
                        }
                        return true;
}

判断是否已经走正确了的代码不可以这样写,否则虽然已经走对了,但是没有n个皇后,就跳出窗口,输出失败。这里做个标记,因为之前犯过错了。这个代码错误的原因是,只有走完了n个皇后,并且全都没有走错,才是胜利的,但是忽略了没有走完,但是没有走错的情况
如图:
在这里插入图片描述

                            if (con && count == 8) {
                            //摆放了n个皇后,而且全部摆放正确,那么跳出窗口,表示胜利了
                                label = new JLabel("WONDERFUL");
                                show();
                            } else{
                            //否则,就跳出失败
                                label = new JLabel("失败了,请再接再励");
                                show();
                            }

这个代码的改正方法只要将else变成else if(!con)即可,当然也可以用下面的代码。

点击按钮,获取对应的二维数组的下标有几点需要注意的是,这也是我想了很久的,我觉得就是这是难点,所以在这里向大家请教,如果有更好的解决办法,请大家指教
①获取的下标取决于窗口的位置,所以不可以移动窗口,否则会错误,因为鼠标的位置改变,从而导致每一行的最小值会改变。
②其次每一行的最小值、间隔取决于设定的窗口的大小,所以并不是固定的
③设定的皇后个数不同,也会影响间隔,所以如果没有更改我们的间隔、那么就会报错或者点击时某一个格子得到的却不是那个格子的皇后,而是其他的格子,如图,这里设置4个皇后的时候:
1)越界错误
在这里插入图片描述
2)点击某一个按钮,但是得到的却不是想要的结果
在这里插入图片描述

完整代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class EightQueenGUI {
    public static ImageIcon imageIcon = new ImageIcon("G:\\百度网盘\\学习路线\\捕获.PNG");
    public static ActionListener actionListener;
    public static int n = 8;//皇后的个数
    public static int count = 0;//统计已经摆放多少个皇后了
    public static int[][] arr = new int[n][n];//表示皇后
    public static JFrame frame = new JFrame();
    public static JButton[][] button = new JButton[n][n];
    public static void paintChess(){
        int i ,j;
        for(i = 0; i<n; i++){
            for(j = 0; j<n;j++){
                button[i][j] = new JButton();//为按钮开辟空间,否则就没有办法实现按钮的相关操作
                button[i][j].setOpaque(true);
                if((i+j)%2==0)
                    button[i][j].setBackground(Color.BLACK);//背景设置黑色
                else
                    button[i][j].setBackground(Color.WHITE);//背景设置白色
                button[i][j].addActionListener(actionListener = new ActionListener() {
                    JFrame myFrame = new JFrame();
                    JPanel panel = new JPanel();
                    JLabel label;
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Point e1 =java.awt.MouseInfo.getPointerInfo().getLocation();//获得当前鼠标的位置,是相对于电脑的的位置
                        int x = (int)e1.getX();//表示行,但是相对于电脑而言,如果没有下面的那一步,那么就会越界,因为会很大
                        int i=(x-210)/59;//当前鼠标的横坐标减去每一行的最小值,然后除以59,(59是每一行的间隔),所以就可以得到相应的下标(注意这一步十分重要,因为x表示的是鼠标的横坐标,那么向右移,经过这一步之后,得到的就是二维数组的列
                        int y = (int)e1.getY();//得到的鼠标当前位置的纵坐标
                        int j = (y-241)/55;//道理同上,由于y是纵坐标,那么向下移动,得到的就是二维数组中的行
                        arr[j][i] = 1;//将对应的值赋为1,表示这里已经放置了皇后
                        count++;
                        button[j][i].setIcon(imageIcon);//二维数组arr和按钮是相对应的,那么就将将当前按钮的位置的背景替换成皇后棋子

                        if(count >1) {
                        //当皇后的数目至少有2个的时候,开始判断是否含有任意两个皇后再同一列、同一行、同一斜线上
                            boolean con = check(j,i);
                            if (!con) {
                            //这里包含了两种情况,首先如果没有n个皇后,但是已经走错了,那么就跳出窗口,表示失败了,然后是已经放了n个皇后,但是还是走错了
                                label = new JLabel("失败了,请再接再励");
                                show();
                            } else if(count==n) {
                            //摆放了n个皇后,而且全部摆放正确,那么跳出窗口,表示胜利了,当没有摆放n个皇后,而且没有走错的情况下,那么就不用跳出窗口
                                label = new JLabel("WONDERFUL");
                                show();
                            }
                        }
                    }

                    /**
                     * 判断任意两个皇后是否在同一行、同一列、同一斜线上
                     * 思路:除去当前位置的皇后不需要遍历,其余的数组中都需要遍历,判断他们的位置是否摆放了皇后,所以需要从0开始遍历
                     * @param x    当前的皇后的横坐标
                     * @param y    当前的皇后的纵坐标
                     * @return     返回在这里摆放皇后是否正确,如果是正确的话,那么就返回true,否则返回false
                     */
                    public boolean check(int x,int y){
                        //判断任意两个皇后是否在同一列
                        for(int i = 0; i <n;i++){
                            if(i != x && arr[i][y] == 1)//如果是同一列,那么就返回false,表示摆放错误
                                return false;
                        }
                        //判断任意两个皇后是否在同一行
                        for(int i = 0; i <n; i++){
                            if(i != y && arr[x][i] == 1)//如果是在同一行,那么就返回false,表示摆放错误
                                return false;
                        }
                        //判断任意两个皇后是否在同一斜线,如果在,那么就返回false,表示摆放错误
                        for(int i = 0; i<n; i++){
                            for(int j = 0; j<n; j++){
                                if(i == x)//如果遍历到的皇后是当前的皇后,那么跳过这个皇后,判断其后面是否有皇后和他在同一斜线上
                                    break;
                                //如果不是当前的皇后,那么开始如果在同一斜线上,那么就返回false,表示摆放错误
                                else if(arr[i][j] == 1 && Math.abs(i - x) == Math.abs(j - y))
                                    return false;
                            }
                        }
                        return true;
                    }
                    public  void show(){
                        panel.add(label);
                        myFrame.setVisible(true);
                        myFrame.add(panel);
                        myFrame.setBounds(300, 300, 200, 100);
                        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    }
                });
                frame.add(button[i][j]);
            }
        }
        frame.setVisible(true);//设置可见
        frame.setTitle("n皇后问题");//窗口的标题
        frame.setLayout(new GridLayout(n,n));//设置布局
        frame.setBounds(200,200,500,500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//退出
    }
    public static void main(String[] args){
            paintChess();//调用方法,从而将窗口添加按钮,并将其变成棋盘状
    }
}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二、 算法思想: 采用回溯法解决八皇后问题。从第一行开始,放第一个皇后,放好皇后以后,她所在的行,列和对角线上的每一个位置就是她的管辖范围,别的皇后没有权利干涉,否则死无藏身之地。 然后,第二个皇后,从第二行的第一列开始判断所在的位置是否是别的皇后的管辖范围,找到第一个还没有被占据的位置,则将其占为己有。暂时,该皇后停在该位置。然后,第三个到第八个皇后依次从第三行,第四行,… ,到第八行的第一列开始寻求自己的位置。假如到第i个皇后时,已经没有任何位置可选,则第i-1个皇后必须往后移动进行协调,同样,假如第i-1个皇后往后移动时没有找到空位置,则第i-2个皇后必须往后移动,进行协调,当找到空位置时,暂时停下,将下一个皇后重新从第一列开始寻找空位置。重复上述过程,直到所有皇后都停下来。则得到了第一个解。要想产生所有的解,则当产生第一个解以后,第八个皇后往后移动,找下一个可以利用的空位置,找不到,则第七个皇后必须往后移动,若找到空位置则停下,第八个皇后从第八行第一列重新试探,找到空位置。一直这样,直到第一个皇后将第一行遍历完。得到的解就是所有解。 三、 概要设计: ***************类型及相关变量定义***************** //位置信息类型 typedef struct { int row; int col; }PosType; //皇后类型 typedef struct Queen{ PosType pos; int number; //第几号皇后 }QueenType; //栈节点类型 typedef struct Note{ QueenType queen; struct Note *next; }NoteType; //棋盘,某一位置chessboard[i][j]上有皇后,则该位的值变为皇后序号。同样,该皇后的势 //力范围内的位置上的值全部变为该皇后的序号。 int chessboard[8][8]; //结果集,共92种解,每一种解中记录8个位置信息。 PosType ResultSet[92][8]; //定义一个栈,保存信息 Typedef struct{ NoteType head; Int size; }QueenStack; //定义一个栈,存放皇后信息 QueenStack qstack; *************相关操作**************** //初始化棋盘,开始时每个位置上都没有皇后,值全为0;并给8个皇后编号。 void initChessboard(); //回溯求八皇后问题的所有解,皇后协调算法 void queenCoordinate(); //输出所有解 void printResult();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值