This is a Knight's Tour problem. The first application:
import java.awt.*;
import java.util.ArrayList;
import java.util.Comparator;
public class GcdsHorse {
private static int X;
private static int Y;
private static boolean[] visited;
private static boolean finished;
public static void main(String[] args) {
System.out.println("the horse has been running");
X = 8;
Y = 8;
int row = 2;
int column = 3;
int[][] chessboard = new int[X][Y];
visited = new boolean[X * Y];
long start = System.currentTimeMillis();
traversalChessboard(chessboard, row - 1, column - 1, 1);
long end = System.currentTimeMillis();
System.out.println("time: " + (end - start) + " ms");
for (int[] rows:chessboard){
for (int steps:rows){
System.out.print(steps+"\t");
}
System.out.println();
}
}
public static void traversalChessboard(int[][] chessboard, int row, int column, int step){
System.out.println(step);
chessboard[row][column] =step;
visited[row * X + column] = true;
ArrayList<Point> ps = getAvailable(new Point(column, row));
sort(ps);
while(!ps.isEmpty()) {
Point p = (Point)ps.remove(0);
if (!visited[p.y * X + p.x]) {
traversalChessboard(chessboard, p.y, p.x, step + 1);
}
}
if (step < X * Y && !finished) {
chessboard[row][column] = 0;
visited[row * X + column] = false;
} else {
finished = true;
}
}
//This method is to get next collection of the position that horse can reach in current position
public static ArrayList<Point> getAvailable(Point curPoint){
ArrayList<Point> ps=new ArrayList<>();
Point p1=new Point();
if ((p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y - 1) >= 0) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y - 2) >= 0) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x + 1) < X && (p1.y = curPoint.y - 2) >= 0) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x + 2) < X && (p1.y = curPoint.y - 1) >= 0) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x + 2) < X && (p1.y = curPoint.y + 1) < Y) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x + 1) < X && (p1.y = curPoint.y + 2) < Y) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y + 2) < Y) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y + 1) < Y) {
ps.add(new Point(p1));
}
return ps;
}
//The core of GCD. This method is to sort the collection of position the horse can reach according to time-consuming.
public static void sort(ArrayList<Point> ps) {
ps.sort(new Comparator<Point>() {
public int compare(Point o1, Point o2) {
int count1 = GcdsHorse.getAvailable(o1).size();
int count2 = GcdsHorse.getAvailable(o2).size();
if (count1 < count2) {
return -1;
} else {
return count1 == count2 ? 0 : 1;
}
}
});
}
}
And the computational results is:
time: 12 ms
2 35 4 19 30 33 14 17
5 20 1 34 15 18 29 32
36 3 62 57 44 31 16 13
21 6 59 54 61 28 43 46
52 37 56 63 58 45 12 27
7 22 53 60 55 64 47 42
38 51 24 9 40 49 26 11
23 8 39 50 25 10 41 48
The cost of time is low. But when I use the same algorithm and the same data in a swing application. It seems like an endless loop. Code is below:
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Comparator;
public class HorsePane extends JFrame implements ActionListener,Runnable{
private static int X;
private static int Y;
private static boolean[] visited;
private static boolean finished;
private JTextField[] texts;
private JButton button;
private DefaultTableModel tableModel;
private JTable jtable;
public Object [] temp= {"no result"};
Thread thread;
public HorsePane(){
super("knigtht's tour");
this.setBounds(400, 300, 800, 360);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel=new JPanel();
this.getContentPane().add(panel,"North");
String[] str_label= {"chessboard's row","chessboard's column","initial row","initial column"};
String[] str_text= {"6","6","1","1"};
this.texts=new JTextField[str_text.length];
for(int i=0; i<str_text.length;i++)
{
panel.add(new JLabel(str_label[i]));
panel.add(this.texts[i]=new JTextField(str_text[i]));
}
panel.add(this.button=new JButton("demonstrate"));
this.button.addActionListener(this);
this.tableModel =new DefaultTableModel();
this.tableModel.setRowCount(0);
this.tableModel.setColumnCount(0);
this. jtable=new JTable (this.tableModel);
this.getContentPane().add(new JScrollPane(jtable));
this.setVisible(true);
}
public static void traversalChessboard(int[][] chessboard, int row, int column, int step){
System.out.println(step);
chessboard[row][column] =step;
visited[row * X + column] = true;
ArrayList<Point> ps = getAvailable(new Point(column, row));
sort(ps);
while(!ps.isEmpty()) {
Point p = (Point)ps.remove(0);
if (!visited[p.y * X + p.x]) {
traversalChessboard(chessboard, p.y, p.x, step + 1);
}
}
if (step < X * Y && !finished) {
chessboard[row][column] = 0;
visited[row * X + column] = false;
} else {
finished = true;
}
}
//This method is to get next collection of the position that horse can reach in current position
public static ArrayList<Point> getAvailable(Point curPoint){
ArrayList<Point> ps=new ArrayList<>();
Point p1=new Point();if ((p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y - 1) >= 0) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y - 2) >= 0) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x + 1) < X && (p1.y = curPoint.y - 2) >= 0) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x + 2) < X && (p1.y = curPoint.y - 1) >= 0) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x + 2) < X && (p1.y = curPoint.y + 1) < Y) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x + 1) < X && (p1.y = curPoint.y + 2) < Y) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y + 2) < Y) {
ps.add(new Point(p1));
}
if ((p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y + 1) < Y) {
ps.add(new Point(p1));
}
return ps;
}
//The core of GCD. This method is to sort the collection of position the horse can reach according to time-consuming.
public static void sort(ArrayList<Point> ps) {
ps.sort(new Comparator<Point>() {
public int compare(Point o1, Point o2) {
int count1 = GcdsHorse.getAvailable(o1).size();
int count2 = GcdsHorse.getAvailable(o2).size();
if (count1 < count2) {
return -1;
} else {
return count1 == count2 ? 0 : 1;
}
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
this.tableModel.setRowCount(0);
this.tableModel.setColumnCount(0);
if(e.getSource() instanceof JButton)
{
this.thread=new Thread(this);
this.thread.start();
}
}
@Override
public void run() {
try {
X=Integer.parseInt(texts[0].getText());
Y=Integer.parseInt(texts[1].getText());
int row=Integer.parseInt(texts[2].getText());
int column=Integer.parseInt(texts[3].getText());
int[][] chessboard = new int[X][Y];
visited = new boolean[X * Y];
finished=false;
traversalChessboard(chessboard, row - 1, column - 1, 1);
if(!finished){
throw new Exception("no result");
}
this.tableModel.setRowCount(X);
this.tableModel.setColumnCount(Y);
for(int i=1;i<=X*Y;i++){
Point p = getIndex(chessboard,i);
this.tableModel.setValueAt(String.format("%d", i),p.x, p.y);
this.thread.sleep(500);
}
this.thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, e.toString());
}
}
public static Point getIndex(int[][] temp1,int temp2){
for (int i=0;i<X;i++){
for(int j=0;j<Y;j++){
if (temp1[i][j]==temp2){
return new Point(i,j);
}
}
}
return null;
}
public static void main(String[] args) {
new HorsePane();
}
}
But in other situation, when I use other data, the second swing application can run. data:6,6,1,1 data:8,8,1,1
I can't find where the reason is.
So, I've been trying to get my head around you code and it's ... interesting.
If I feed in
x=8,y=8,row=2andcolumn=2into both implementations, both give back the same values, having said that, you can reduce some of the potential risk of issues by using the exact same algorithmStart by defining a single class which does all the work...
Note, I've removed a lot of
staticfrom your code, this isn't helping you.For the text based solution, it might look something like this...
For me, this prints
The UI is slightly more complicated. Swing isn't thread safe and it's single threaded.
This basically means that you shouldn't run any long running operations within the context of the Event Dispatching Thread and you shouldn't update the UI (or a state the UI relies on) from outside the context of the EDT
See Concurrency in Swing for more details.
Now, for this solution, I would use a
SwingWorker, see Worker Threads and SwingWorker for more detailsAnd finally the actual pane itself...
Now, when I run it, the worker will dump out
to the console and the UI ....
Honestly, I can only speculate, but I would surmise that:
Runnable example