Java八數碼(圖形介面)
阿新 • • 發佈:2019-02-10
最近學習了Java圖形介面的程式設計,寫一個八數碼bfs的程式碼,和大家分享一下。
同時這份程式碼也是我的期末大作業。
邏輯層
package com.EightNumber.view; import java.util.*; public class EightNumPath { final static int dx[] = {-1, 1, 0, 0}; final static int dy[] = { 0, 0,-1, 1}; final static String dir = "UDLR"; static int maxstate = 400000; static int [][]st = new int[maxstate][9]; static int []goal = {1,2,3,4,5,6,7,8,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[9]; static StringBuffer path; public static boolean isok(int []a) { int sum=0; for(int i=0; i < 9; i++) for(int j=i+1; j < 9; 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[0] = 1; for(int i = 1; i < 9; i++) { fact[i] = fact[i-1] * i; } Arrays.fill(vis, false); } private static boolean try_to_insert(int s) { int code = 0; for(int i = 0; i < 9; i++) { int cnt = 0; for(int j = i+1; j < 9; j++) { if(st[s][j] < st[s][i]) { cnt++; } } code += fact[8-i] * cnt; } if(vis[code]) { return false; } return vis[code] = true; } private static void print_path(int cur) { while(cur != 1) { path.insert(0,dir.charAt(move[cur])); cur = fa[cur]; } } private static int bfs() { init_lookup_table(); int front = 1 , rear = 2; try_to_insert(front); while(front < rear) { if(Arrays.equals(st[front], goal)) { return front; } int z; for(z = 0; z < 9; z++) { if(st[front][z] == 0) { break; } } int x = z/3, y = z%3; for(int d = 0; d < 4; d++) { int newx = x + dx[d]; int newy = y + dy[d]; int newz = newx * 3 + newy; if(newx >= 0 && newx < 3 && newy >= 0 && newy < 3) { 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.charAt(i)) - '0'; } int ans = bfs(); print_path(ans); return path.toString(); } }
介面層
package com.EightNumber.view; import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.util.*; public class EightNumFrame extends Frame implements ActionListener,KeyListener { MenuBar menubar=new MenuBar(); Menu menu_file = new Menu("檔案(F)"); MenuItem restart = new MenuItem("重新開始"); MenuItem nextPath = new MenuItem("提示"); MenuItem printPath = new MenuItem("還原"); MenuItem exit = new MenuItem("退出"); Button[] button; Panel panel; int row,col; private static int position,cellNum; final int dr[] = { 0,-1, 0, 1}; final int dc[] = {-1, 0, 1, 0}; public EightNumFrame(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_file.add(nextPath); menu_file.add(printPath); menu_file.add(exit); menubar.add(menu_file); panel = new Panel(new GridLayout(row,col)) ; button = new Button[cellNum]; 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[i].setFont(new Font("Courier", 1, 20)); button[i].addActionListener(this); button[i].addKeyListener(this); panel.add(button[i]); } position = cellNum - 1; 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[9]; do { int k = 0; Random random=new Random(); Set<Integer> set=new HashSet<Integer>(); while(set.size() < cellNum-1) { int n=random.nextInt(cellNum-1)+1; if(!set.contains(n)) { set.add(n); a[k++] = n; } } a[k] = 0; }while(!EightNumPath.isok(a)); for(int i = 0; i < 9; 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(" ")) { return false; }else if(Integer.valueOf(button[i].getLabel()) != i+1) { return false; } } return true; } private boolean judge(Button a, Button 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) { StringBuffer state = new StringBuffer(); 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.append('0'); }else { state.append(button[i].getLabel()); } } String path = EightNumPath.solve(state.toString()); JOptionPane.showMessageDialog(this,"建議走:"+path); System.out.println(path); return; }else if(e.getSource() == printPath) { for(int i = 0; i < cellNum; i++) { if(button[i].getLabel().equals(" ")) { state.append('0'); }else { state.append(button[i].getLabel()); } } String path = EightNumPath.solve(state.toString()); 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(1000); } 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"); } } public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} public static void main(String[] args) { new EightNumFrame(3, 3); } }