1、問題描述:
在N*N棋盤上,任意一個位置放置一個棋子馬,要能選擇一套合適的移動路線,按象棋中“馬走日”的移動規則不重復地遍歷棋盤上每一個位置點。
2、基本要求:
用圖形化的界面顯示結果。
3、設計思路:
(1) 首先要考慮,落下馬的位置,馬可能走到的位置,即最初定義兩個數組分別儲存馬在二維空間中可能跳躍的八個位置。
(2) 其次是要用到遞歸的方法解決馬不斷跳躍的問題,所以要學會遞歸的基本思想,遞歸思想就是多次調用自身,也就是用解決一次馬跳躍的問題就意味着可以多次解決馬跳躍的問題。
(3) 最后要考慮到回溯,馬的跳躍不可能是一帆風順的,當碰到阻礙時,馬需要跳回原來的位置重新選擇路線。
(4) 最后設計到一些界面設計問題,比如調節窗口大小、字體大小和顏色、標題等等。
4、源代碼:
(1)無蹩腳
5×5
package cn.test.termtest.uglynumber; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class TestChess extends JFrame implements ActionListener { static JButton button[][]; //棋盤的按鈕 static int boardSize; //棋盤大小(行數/列數) static int count; //落子的順序 JLabel promptLabel =new JLabel(); //提示信息標簽 //馬走日子的偏坐標 static int dx[] = {1,2,2,1,-1,-2,-2,-1}; static int dy[] = {2,1,-1,-2,-2,-1,1,2}; public static void main(String[] args) { boardSize =5; TestChess testChess =new TestChess(); } public TestChess() { count =1; //定義font為微軟雅黑,普通,12號 Font font =new Font("宋體",Font.PLAIN,12); this.setTitle("象棋中馬的遍歷"); JPanel p1 =new JPanel(); //正式面板 p1.setLayout(new GridLayout(boardSize,boardSize)); //GridLayout為網格布局 button =new JButton[boardSize+1][boardSize+1]; int n=1; for(int i=1;i<=boardSize;i++) for(int j=1;j<=boardSize;j++) { button[i][j]=new JButton(); button[i][j].setActionCommand(String.valueOf(n++));//動作命令,並非按鈕上面的字,區別是哪個按鈕 button[i][j].setFont(font); button[i][j].addActionListener(this);//添加監聽 p1.add(button[i][j]); } add(p1,BorderLayout.CENTER);//面板添加到窗口當中 JPanel p2 =new JPanel(); promptLabel =new JLabel(); promptLabel.setForeground(Color.RED); promptLabel.setText("提示:單擊某一個按鈕,作為馬的起始位置"); p2.add(promptLabel); add(p2,BorderLayout.SOUTH); setSize(300,200); this.setLocationRelativeTo(null); setVisible(true); } public void actionPerformed(ActionEvent e) { String buttonKey =e.getActionCommand(); int intKey = Integer.parseInt(buttonKey); int row =intKey /boardSize +1; int col= intKey%boardSize; button[row][col].setText("1"); if(DFS(row,col)) promptLabel.setText("提示:遍歷成功"); else promptLabel.setText("提示:遍歷失敗"); } static boolean DFS(int x,int y) { //經過了所有的空位置 if(count == boardSize*boardSize) return true; //遍歷從當前點走日字能夠到達的8個點 for(int dir =0;dir<8;dir++) { //走日字到達下一個點 int next_x =x+dx[dir]; int next_y =y+dy[dir]; //超出邊界 if(next_x<1 || next_x > boardSize || next_y<1 || next_y>boardSize) continue; if(!button[next_x][next_y].getText().equals("")) continue; //訪問過的點計數 count++; button[next_x][next_y].setText(String.valueOf(count)); if(DFS(next_x,next_y)) return true; //從日字的一個對角線出發不能到達所有的位置 count--;//后退一步 button[next_x][next_y].setText(""); } return false; } }
(2)無蹩腳
8×8
package cn.test.termtest.uglynumber; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class TestChess extends JFrame implements ActionListener { static JButton button[][]; //棋盤的按鈕 static int boardSize; //棋盤大小(行數/列數) static int count; //落子的順序 JLabel promptLabel =new JLabel(); //提示信息標簽 //馬走日子的偏坐標 static int dx[] = {1,2,2,1,-1,-2,-2,-1}; static int dy[] = {2,1,-1,-2,-2,-1,1,2}; public static void main(String[] args) { boardSize =8; TestChess testChess =new TestChess(); } public TestChess() { count =1; //定義font為微軟雅黑,普通,12號 Font font =new Font("宋體",Font.PLAIN,12); this.setTitle("象棋中馬的遍歷"); JPanel p1 =new JPanel(); //正式面板 p1.setLayout(new GridLayout(boardSize,boardSize)); //GridLayout為網格布局 button =new JButton[boardSize+1][boardSize+1]; int n=1; for(int i=1;i<=boardSize;i++) for(int j=1;j<=boardSize;j++) { button[i][j]=new JButton(); button[i][j].setActionCommand(String.valueOf(n++));//動作命令,並非按鈕上面的字,區別是哪個按鈕 button[i][j].setFont(font); button[i][j].addActionListener(this);//添加監聽 p1.add(button[i][j]); } add(p1,BorderLayout.CENTER);//面板添加到窗口當中 JPanel p2 =new JPanel(); promptLabel =new JLabel(); promptLabel.setForeground(Color.RED); promptLabel.setText("提示:單擊某一個按鈕,作為馬的起始位置"); p2.add(promptLabel); add(p2,BorderLayout.SOUTH); setSize(300,200); this.setLocationRelativeTo(null); setVisible(true); } public void actionPerformed(ActionEvent e) { String buttonKey =e.getActionCommand(); int intKey = Integer.parseInt(buttonKey); int row =intKey /boardSize +1; int col= intKey%boardSize; button[row][col].setText("1"); if(DFS(row,col)) promptLabel.setText("提示:遍歷成功"); else promptLabel.setText("提示:遍歷失敗"); } static boolean DFS(int x,int y) { //經過了所有的空位置 if(count == boardSize*boardSize) return true; //遍歷從當前點走日字能夠到達的8個點 for(int dir =0;dir<8;dir++) { //走日字到達下一個點 int next_x =x+dx[dir]; int next_y =y+dy[dir]; //超出邊界 if(next_x<1 || next_x > boardSize || next_y<1 || next_y>boardSize) continue; if(!button[next_x][next_y].getText().equals("")) continue; //訪問過的點計數 count++; button[next_x][next_y].setText(String.valueOf(count)); if(DFS(next_x,next_y)) return true; //從日字的一個對角線出發不能到達所有的位置 count--;//后退一步 button[next_x][next_y].setText(""); } return false; } }
(3)有蹩腳
5×5
package cn.test.termtest.uglynumber; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class TestChess extends JFrame implements ActionListener { static JButton button[][]; //棋盤的按鈕 static int boardSize; //棋盤大小(行數/列數) static int count; //落子的順序 static int obstacleNum; JLabel promptLabel =new JLabel(); //提示信息標簽 //馬走日子的偏坐標 static int dx[] = {1,2,2,1,-1,-2,-2,-1}; static int dy[] = {2,1,-1,-2,-2,-1,1,2}; public static void main(String[] args) { boardSize =5; TestChess testChess =new TestChess(); } public TestChess() { count =1; //定義font為微軟雅黑,普通,12號 Font font =new Font("宋體",Font.PLAIN,12); this.setTitle("象棋中馬的遍歷"); JPanel p1 =new JPanel(); //正式面板 p1.setLayout(new GridLayout(boardSize,boardSize)); //GridLayout為網格布局 button =new JButton[boardSize+1][boardSize+1]; int n=1; for(int i=1;i<=boardSize;i++) for(int j=1;j<=boardSize;j++) { button[i][j]=new JButton(); button[i][j].setActionCommand(String.valueOf(n++));//動作命令,並非按鈕上面的字,區別是哪個按鈕 button[i][j].setFont(font); button[i][j].addActionListener(this);//添加監聽 p1.add(button[i][j]); } button[1][1].setText("卒"); button[5][1].setText("卒"); obstacleNum=2; add(p1,BorderLayout.CENTER);//面板添加到窗口當中 JPanel p2 =new JPanel(); promptLabel =new JLabel(); promptLabel.setForeground(Color.RED); promptLabel.setText("提示:單擊某一個按鈕,作為馬的起始位置"); p2.add(promptLabel); add(p2,BorderLayout.SOUTH); setSize(300,200); this.setLocationRelativeTo(null); setVisible(true); } public void actionPerformed(ActionEvent e) { String buttonKey =e.getActionCommand(); int intKey = Integer.parseInt(buttonKey); int row =intKey /boardSize +1; int col= intKey%boardSize; button[row][col].setText("1"); if(DFS(row,col)) promptLabel.setText("提示:遍歷成功"); else promptLabel.setText("提示:遍歷失敗"); } static boolean DFS(int x,int y) { //經過了所有的空位置 if(count == boardSize*boardSize-obstacleNum) return true; //遍歷從當前點走日字能夠到達的8個點 for(int dir =0;dir<8;dir++) { //走日字到達下一個點 int next_x =x+dx[dir]; int next_y =y+dy[dir]; //超出邊界 if(next_x<1 || next_x > boardSize || next_y<1 || next_y>boardSize) continue; if(!button[next_x][next_y].getText().equals("")) continue; //訪問過的點計數 count++; button[next_x][next_y].setText(String.valueOf(count)); if(DFS(next_x,next_y)) return true; //從日字的一個對角線出發不能到達所有的位置 count--;//后退一步 button[next_x][next_y].setText(""); } return false; } }
5、運行結果:
(1)
(2)
(3)