0

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();
    }
}

The endless loop

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.

false
  • 10,264
  • 13
  • 101
  • 209
  • 1
    It looks like your first application is a commandline tool, i.e. it contains some i/o but mostly the algorithm. I would suggest you extract the algorithm into a class, i.e. separate i/o from it and also keep data as instance variables instead of statics. Once that's done you should be able to reuse the algorithm class in your Swing application and replace command line i/o with Swing-based i/o. That way you can test your algorithm separately and if it works in one case but not the other you know that the problem is with your i/o and you can debug that portion. – Thomas Dec 09 '21 at 08:12
  • You have a thread.sleep in your UI and you're wondering why it takes longer? Also, Swing is not thread safe – MadProgrammer Dec 09 '21 at 08:55

1 Answers1

1

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=2 and column=2 into 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 algorithm

Start by defining a single class which does all the work...

public class KnightsTour {

    private int x, y;
    private boolean[] visited;
    private boolean finished;

    public KnightsTour(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int[][] start(int row, int column) {
        int[][] chessboard = new int[x][y];
        visited = new boolean[x * y];
        finished = false;

        traversalChessboard(chessboard, row - 1, column - 1, 1);
        return chessboard;
    }

    protected void traversalChessboard(int[][] chessboard, int row, int column, int 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
    protected 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.
    protected void sort(ArrayList<Point> ps) {
        ps.sort(new Comparator<Point>() {
            public int compare(Point o1, Point o2) {
                int count1 = getAvailable(o1).size();
                int count2 = getAvailable(o2).size();
                if (count1 < count2) {
                    return -1;
                } else {
                    return count1 == count2 ? 0 : 1;
                }
            }
        });
    }
}

Note, I've removed a lot of static from your code, this isn't helping you.

For the text based solution, it might look something like this...

Instant startedAt = Instant.now();
int[][] chessboard = new KnightsTour(8, 8).start(2, 3);
Duration duration = Duration.between(startedAt, Instant.now());
System.out.println("time: " + (duration.toMillis()) + " ms");
for (int[] rows : chessboard) {
    for (int steps : rows) {
        System.out.print(steps + "\t");
    }
    System.out.println();
}

For me, this prints

time: 4 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 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 details

// This just allows me to move data from one thread context to another
protected class DataPoint {

    private int x, y, value;

    public DataPoint(int x, int y, int value) {
        this.x = x;
        this.y = y;
        this.value = value;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getValue() {
        return value;
    }

}

// nb you could actually pass a pre-filled instance of 
// KnightsTour, but we do need some of the properties
// so it's up to you
public class KingsTourWorker extends SwingWorker<Void, DataPoint> {

    private DefaultTableModel model;
    private int x;
    private int y;
    private int startRow;
    private int startColumn;

    public KingsTourWorker(DefaultTableModel model, int x, int y, int startRow, int startColumn) {
        this.x = x;
        this.y = y;
        this.startRow = startRow;
        this.startColumn = startColumn;
        this.model = model;
    }

    @Override
    protected Void doInBackground() throws Exception {
        Instant startedAt = Instant.now();
        int[][] chessboard = new KnightsTour(x, y).start(startRow, startColumn);
        Duration duration = Duration.between(startedAt, Instant.now());
        System.out.println("time: " + (duration.toMillis()) + " ms");
        for (int[] rows : chessboard) {
            for (int steps : rows) {
                System.out.print(steps + "\t");
            }
            System.out.println();
        }
        for (int i = 1; i <= x * y; i++) {
            Point p = getIndex(chessboard, i);
            publish(new DataPoint(p.x, p.y, i));
            Thread.sleep(25);
        }
        return null;
    }

    @Override
    protected void process(List<DataPoint> chunks) {
        for (DataPoint dp : chunks) {
            model.setValueAt(dp.getValue(), dp.getX(), dp.getY());
        }
    }

    private 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;
    }
}

And finally the actual pane itself...

public class HorsePane extends JPanel implements ActionListener {

    private JTextField[] texts;
    private JButton button;
    private DefaultTableModel tableModel;
    private JTable jtable;
    public Object[] temp = {"no result"};

    public HorsePane() {
        setLayout(new BorderLayout());
        JPanel panel = new JPanel();
        add(panel, "North");

        String[] str_label = {"chessboard's row", "chessboard's column", "initial row", "initial column"};
        String[] str_text = {"8", "8", "2", "3"};
        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);
        add(new JScrollPane(jtable));
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        this.tableModel.setRowCount(0);
        this.tableModel.setColumnCount(0);
        if ("demonstrate".equals(e.getActionCommand())) {
            int x = Integer.parseInt(texts[0].getText());
            int y = Integer.parseInt(texts[1].getText());
            this.tableModel.setRowCount(x);
            this.tableModel.setColumnCount(y);
            int startRow = Integer.parseInt(texts[2].getText());
            int startColumn = Integer.parseInt(texts[3].getText());

            button.setEnabled(false);

            KingsTourWorker worker = new KingsTourWorker(tableModel, x, y, startRow, startColumn);
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if (worker.getState() == SwingWorker.StateValue.DONE) {
                        button.setEnabled(true);
                    }
                }
            });
            worker.execute();
        }
    }

}

Now, when I run it, the worker will dump out

time: 1 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

to the console and the UI ....

enter image description here

But why doesn't mine work

Honestly, I can only speculate, but I would surmise that:

  • In violating the single threaded nature of the API, you've broken it
  • You are running more than one thread simultaneously and this is generating conflicts. You will note in my code, I disable the button while the worker is running

Runnable example

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;

public class Test {

    public static void main(String[] args) {
        new Test();

    }

    public Test() {
        Instant startedAt = Instant.now();
        int[][] chessboard = new KnightsTour(8, 8).start(2, 3);
        Duration duration = Duration.between(startedAt, Instant.now());
        System.out.println("time: " + (duration.toMillis()) + " ms");
        for (int[] rows : chessboard) {
            for (int steps : rows) {
                System.out.print(steps + "\t");
            }
            System.out.println();
        }
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new HorsePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class KnightsTour {

        private int x, y;
        private boolean[] visited;
        private boolean finished;

        public KnightsTour(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int[][] start(int row, int column) {
            int[][] chessboard = new int[x][y];
            visited = new boolean[x * y];
            finished = false;

            traversalChessboard(chessboard, row - 1, column - 1, 1);
            return chessboard;
        }

        protected void traversalChessboard(int[][] chessboard, int row, int column, int 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
        protected 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.
        protected void sort(ArrayList<Point> ps) {
            ps.sort(new Comparator<Point>() {
                public int compare(Point o1, Point o2) {
                    int count1 = getAvailable(o1).size();
                    int count2 = getAvailable(o2).size();
                    if (count1 < count2) {
                        return -1;
                    } else {
                        return count1 == count2 ? 0 : 1;
                    }
                }
            });
        }
    }

    public class HorsePane extends JPanel implements ActionListener {

        private JTextField[] texts;
        private JButton button;
        private DefaultTableModel tableModel;
        private JTable jtable;
        public Object[] temp = {"no result"};

        public HorsePane() {
            setLayout(new BorderLayout());
            JPanel panel = new JPanel();
            add(panel, "North");

            String[] str_label = {"chessboard's row", "chessboard's column", "initial row", "initial column"};
            String[] str_text = {"8", "8", "2", "3"};
            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);
            add(new JScrollPane(jtable));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            this.tableModel.setRowCount(0);
            this.tableModel.setColumnCount(0);
            if ("demonstrate".equals(e.getActionCommand())) {
                int x = Integer.parseInt(texts[0].getText());
                int y = Integer.parseInt(texts[1].getText());
                this.tableModel.setRowCount(x);
                this.tableModel.setColumnCount(y);
                int startRow = Integer.parseInt(texts[2].getText());
                int startColumn = Integer.parseInt(texts[3].getText());

                button.setEnabled(false);

                KingsTourWorker worker = new KingsTourWorker(tableModel, x, y, startRow, startColumn);
                worker.addPropertyChangeListener(new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        if (worker.getState() == SwingWorker.StateValue.DONE) {
                            button.setEnabled(true);
                        }
                    }
                });
                worker.execute();
            }
        }

    }

    protected class DataPoint {

        private int x, y, value;

        public DataPoint(int x, int y, int value) {
            this.x = x;
            this.y = y;
            this.value = value;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public int getValue() {
            return value;
        }

    }

    public class KingsTourWorker extends SwingWorker<Void, DataPoint> {

        private DefaultTableModel model;
        private int x;
        private int y;
        private int startRow;
        private int startColumn;

        public KingsTourWorker(DefaultTableModel model, int x, int y, int startRow, int startColumn) {
            this.x = x;
            this.y = y;
            this.startRow = startRow;
            this.startColumn = startColumn;
            this.model = model;
        }

        @Override
        protected Void doInBackground() throws Exception {
            Instant startedAt = Instant.now();
            int[][] chessboard = new KnightsTour(x, y).start(startRow, startColumn);
            Duration duration = Duration.between(startedAt, Instant.now());
            System.out.println("time: " + (duration.toMillis()) + " ms");
            for (int[] rows : chessboard) {
                for (int steps : rows) {
                    System.out.print(steps + "\t");
                }
                System.out.println();
            }
            for (int i = 1; i <= x * y; i++) {
                Point p = getIndex(chessboard, i);
                publish(new DataPoint(p.x, p.y, i));
                Thread.sleep(25);
            }
            return null;
        }

        @Override
        protected void process(List<DataPoint> chunks) {
            for (DataPoint dp : chunks) {
                model.setValueAt(dp.getValue(), dp.getX(), dp.getY());
            }
        }

        private 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;
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thank you very much! I also think that the problem is about swing thread. But my teacher told me I should continue to polish up my algorithmn. LOL, thanks again! – Frederick_Chen Dec 09 '21 at 16:09
  • Despite my time cost has reached 10ms level, she still attribute the problem to algorithmn.Oh, well, so I was lost for a long time today. – Frederick_Chen Dec 09 '21 at 16:14
  • Wait a minute, bro. I just found that my second appliation's method "sort" didn't use it's own method "getAvailable". Instead, I use the GcdsHorse's. The I polish it up. Now it can run with no barrier. Oops, what's this for? Also about thread? – Frederick_Chen Dec 12 '21 at 07:38
  • @Frederick_Chen Welcome to the wonderful world of why you shouldn't be using `static`, but I stand by my statement, isolate the functionality so that both cases are using class – MadProgrammer Dec 12 '21 at 07:43