十五数码之宽度优先搜索

来源:互联网 发布:dev-c 软件下载 编辑:程序博客网 时间:2024/05/21 17:58

在用宽度优先搜索写了八数码之后,又想着写一下15数码,在八数码的基础上做了一些更改,比如字符数组的截取,还有内存的大小更改,但是还是不尽人意,给大家看看吧,希望大家能给些意见,准备用A星算法重新写一下十五数码,看看有什么效果。。。。

算法部分:

import java.util.*;public class Fifteennumberpath {    final static int dx[] = {-1, 1, 0, 0};    final static int dy[] = { 0, 0,-1, 1};    final static String dir = "UDLR";    static int maxstate =40000000;    static int [][]st = new int[maxstate][16];    static int []goal = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};    static int []dist = new int[maxstate];    static int []fa = new int[maxstate];    static int []move = new int[maxstate];    static boolean []vis = new boolean[maxstate];    static int []fact = new int[16];    static StringBuffer path;    public static boolean isok(int []a) //判断数组中的逆序数,如果为偶数返回true,否则返回false;    {        int sum=0;        for(int i=0; i < 16; i++)            for(int j=i+1; j < 16; j++)                  if(a[j] != 0 && a[i] != 0 && a[i] > a[j])                      sum++;        if(sum % 2 == 0) {            return true;        }        return false;    }      private static void init_lookup_table()//将数组fact初始化为1,1,2,6,24,120,720,5080,40640     {        fact[0] = 1;        for(int i = 1; i < 16; i++) {            fact[i] = fact[i-1] * i;        }        Arrays.fill(vis, false);//将数组fill中的元素全部用FALSE来填充,也是一个初始化    }    private static boolean try_to_insert(int s) {        int code = 0;        for(int i = 0; i < 16; i++) {            int cnt = 0;            for(int j = i+1; j < 16; j++) {                if(st[s][j] < st[s][i]) {                    cnt++;//判断逆序数的数量,从S行的第一个元素到最后一个元素分别比较,                }            }            code += fact[15-i] * cnt;//S行的第一个元素与fact数组第一个的积的和相加,交叉积之和        }        if(vis[code]) {            return false;//判断vis[code]的值为真的话返回FALSE        }        return vis[code] = true;//判断vis[code]的值不为真的话返回true    }    private static void print_path(int cur) {        while(cur != 1) {            path.insert(0,dir.charAt(move[cur]));//在索引0的位置插入UDRL中一个,由输入的cur来决定            cur = fa[cur];//然后给cur赋值fa数组中索引0的数        }    }    private static int bfs() {  //宽度优先搜索        init_lookup_table(); //将数组fact初始化为1,1,2,6,24,120,720,5080,40640        int front = 1 , rear = 2;        try_to_insert(front);//判断st[front][]这一行中对应的逆序数和        while(front < rear) {            if(Arrays.equals(st[front], goal)) //如果st[front]这一行与goal相等,返回front            {                return front;            }            int z;            for(z = 0; z < 16; z++)             {                if(st[front][z] == 0)                 {                    break;//当st[front]中出现某个元素为0,跳出,z标记为开始为0的下标                }            }            int x = z/4, y = z%4;            for(int d = 0; d < 4; d++) {                int newx = x + dx[d];                int newy = y + dy[d];                int newz = newx * 4 + newy;                if(newx >= 0 && newx < 4&& newy >= 0 && newy < 4) {                    st[rear] = Arrays.copyOf(st[front], st[front].length);                    st[rear][newz] = st[front][z];                    st[rear][z] = st[front][newz];                    dist[rear] = dist[front] + 1;                    if(try_to_insert(rear)) {                        fa[rear] = front;                        move[rear] = d;                        rear++;                    }                }            }            front++;        }        return 0;    }    public static String solve(String state[])     {        path = new StringBuffer();        for(int i = 0; i < state.length; i++)         {            st[1][i] = Integer.valueOf(state[i]);            System.out.println(state[i]);        }        int ans = bfs();        print_path(ans);        return path.toString();    }}




UI界面部分:


import java.awt.*;import javax.swing.*;import java.awt.event.*;import java.nio.file.Path;import java.util.*; public class FifteennumberFram extends Frame implements ActionListener,KeyListener{    MenuBar menubar=new MenuBar();//创建新的菜单栏    //Menu menu_file = new Menu("文件(F)");//创建下拉菜单文件    //Menu menu_file1 = new Menu("文件(F)");    Button restart = new Button("随机打乱");//在下拉菜单中设置选项    Button nextPath = new Button("提示");    Button printPath = new Button("开始");    Button exit = new Button("退出程序");    Button[] button;//创建按钮    Panel panel;//创建面板panel    Panel panel1;    int row,col;//设置行数和列数    private static int position,cellNum;//用来保存位置和行列乘积数量的变量    final int dr[] = { 0,-1, 0, 1};    final int dc[] = {-1, 0, 1, 0};    public FifteennumberFram(int row,int col) {        super.setMenuBar(menubar);//Windows风格         try         {            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");        }         catch (Exception e)         {            e.printStackTrace();        }        this.row = row;        this.col = col;        cellNum = row*col;        restart.addActionListener(this);        exit.addActionListener(this);        nextPath.addActionListener(this);        printPath.addActionListener(this);        //menu_file.add(restart);//将选项添加到菜单中        //menu_file1.add(restart);        //menu_file.add(printPath);        //menu_file.add(nextPath);        //menu_file.add(exit);        //menubar.add(menu_file);//将菜单添加到菜单栏中                 panel = new Panel(new GridLayout(row,col)) ;        panel1 = new Panel(new GridLayout(1,4)) ;        panel1.add(restart);        panel1.add(nextPath);        panel1.add(printPath);        panel1.add(exit);        button = new Button[cellNum];//创建按钮数目,9个        for(int i = 0; i < cellNum; i++) {        if(i == cellNum - 1) {//初始化按钮上的数字                button[i] = new Button(" ");//最后一个为空            }else {                button[i] = new Button(String.valueOf(i + 1));//其他按钮为对应的数字            }        /*button[0]=new Button("1");        button[1]=new Button("2");        button[2]=new Button("3");        button[3]=new Button("8");        button[4]=new Button(" ");        button[5]=new Button("4");        button[6]=new Button("7");        button[7]=new Button("6");        button[8]=new Button("5");*/        button[i].setFont(new Font("宋体", 1, 20));//设置按钮上显示的数字的字体            button[i].addActionListener(this);//添加监听            button[i].addKeyListener(this);//添加响应            panel.add(button[i]);//在面板上添加按钮        }        position = cellNum - 1;        this.add(BorderLayout.NORTH,panel1);        this.add(BorderLayout.CENTER,panel);//面板排列方式        this.setTitle("十五数码");//文件设置标题        this.setVisible(true);//可显示,必须        this.setSize(300,300);//设置页面的大小        Toolkit kit = Toolkit.getDefaultToolkit();        Dimension screenSize = kit.getScreenSize();        int screenWidth = screenSize.width/2;        int screenHeight = screenSize.height/2;        int height = this.getHeight();        int width = this.getWidth();        this.setLocation(screenWidth-width/2, screenHeight-height/2);        this.addWindowListener(new WindowAdapter()         {            public void windowClosing(WindowEvent e)             {                System.exit(0);            }        });    }    void start()//对于按钮上的数字进行随机排列    {        int a[] = new int[16];        do {            int k = 0;            Random random=new Random();            //调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0            Set set=new HashSet();//不允许出现重复元素            while(set.size() < cellNum-1) {                int n=random.nextInt(cellNum-1)+1;                //保证产生的随机数在1-15之间,且不重复,写入set集合中                if(!set.contains(n)) {                    set.add(n);                    a[k++] = n;                }            }            a[k] = 0;        }while(!Fifteennumberpath.isok(a));        for(int i = 0; i < 16; i++)            button[i].setLabel(String.valueOf(a[i]));        button[cellNum-1].setLabel(" ");        position = cellNum - 1;    }    boolean win()    {        for(int i = 0; i < cellNum - 1; i++)         {        if(button[i].getLabel().equals(" "))//获取每一个按钮的值,如果为空,返回false            {                return false;            }            else if(Integer.valueOf(button[i].getLabel()) != i+1)            //如果对应的按钮与初始化的时候不一致,也返回false            {                return false;            }            /*if(Integer.valueOf(button[0].getLabel()) !=1)            return false;            else if(Integer.valueOf(button[1].getLabel()) !=2)            return false;            else if(Integer.valueOf(button[2].getLabel()) !=3)            return false;            else if(Integer.valueOf(button[3].getLabel()) !=8)            return false;            else if(Integer.valueOf(button[5].getLabel()) !=4)            return false;            else if(Integer.valueOf(button[6].getLabel()) !=7)            return false;            else if(Integer.valueOf(button[7].getLabel()) !=6)            return false;            else if(Integer.valueOf(button[8].getLabel()) !=5)            return false;            else if(button[4].getLabel().equals(" "))            return false;*/        }        return true;//要是与设定的对应的话返回true    }    private boolean judge(Button a, Button b)    //判断按钮a和b之间的位置关系,相邻的话返回true,否则返回false    //(dr,dc)=(0,-1)代表a在b的下方    //(dr,dc)=(-1,0)代表a在b的左方    //(dr,dc)=(0,1)代表a在b的上方    //(dr,dc)=(1,1)代表a在b的右方    {        for(int i = 0; i < 4; i++)         {            if((a.getX()==b.getX()+dr[i]*a.getWidth())&&(a.getY()==b.getY()+dc[i]*a.getHeight()))            {                return true;            }        }        return false;    }        public void actionPerformed(ActionEvent e)     {        String[] state = new String[cellNum];        if(e.getSource() == restart)         {            start();            return;        }        else if(e.getSource() == exit)         {            System.exit(0);            return;        }        else if(e.getSource() == nextPath)         {            for(int i = 0; i < cellNum; i++)             {                if(button[i].getLabel().equals(" "))                {                    state[i]="0";                }                else                 {                    state[i]=button[i].getLabel();                }            }            System.out.println(state);            String path = Fifteennumberpath.solve(state);            //调用写的bfs算法            JOptionPane.showMessageDialog(this,"建议走:"+path+" 一共"+path.length()+"步!");            return;        }        else if(e.getSource() == printPath)         {            for(int i = 0; i < cellNum; i++)             {                if(button[i].getLabel().equals(" "))                 {                state[i]="0";                }                else                 {                state[i]=button[i].getLabel();                }            }            String path = Fifteennumberpath.solve(state);            for(int i = 0; i < path.length(); i++)             {                switch(path.charAt(i))                 {                case 'U':                    go(KeyEvent.VK_UP);                    break;                case 'D':                    go(KeyEvent.VK_DOWN);                    break;                case 'L':                    go(KeyEvent.VK_LEFT);                    break;                case 'R':                    go(KeyEvent.VK_RIGHT);                    break;                }                try {                    Thread.sleep(500);                }                 catch (InterruptedException e1)                 {                    e1.printStackTrace();                }            }        }        for(int i = 0; i < cellNum; i++) {            if(e.getSource() == button[i]) {                if(!button[i].getLabel().equals(" ") && judge(button[i],button[position])) {                    button[position].setLabel(button[i].getLabel());                    button[i].setLabel(" ");                    position = i;                }            }        }        if(win()) {            JOptionPane.showMessageDialog(this,"Congratulations");        }    }    void go(int dir) {        int x = position / col;        int y = position % col;        switch(dir) {        case KeyEvent.VK_UP:            if(x != 0) {                button[position].setLabel(button[position-col].getLabel());                button[position-col].setLabel(" ");                position -= col;            }            break;        case KeyEvent.VK_DOWN:            if(x != row-1) {                button[position].setLabel(button[position+col].getLabel());                button[position+col].setLabel(" ");                position += col;            }            break;        case KeyEvent.VK_LEFT:            if(y != 0) {                button[position].setLabel(button[position-1].getLabel());                button[position-1].setLabel(" ");                position -= 1;            }            break;        case KeyEvent.VK_RIGHT:            if(y != col-1) {                button[position].setLabel(button[position+1].getLabel());                button[position+1].setLabel(" ");                position += 1;            }            break;        }    }    public void keyPressed(KeyEvent e) {        go(e.getKeyCode());        if(win()) {            JOptionPane.showMessageDialog(this,"Congratulations");            //JOptionPane.showMessageDialog(this,this.nextPath);        }    }    public void keyReleased(KeyEvent e) {}    public void keyTyped(KeyEvent e) {}    public static void main(String[] args) {        new FifteennumberFram(4, 4);    }}



1 0