简体   繁体   English

Java多线程数独难题

[英]Multithreading Sudoku Puzzle in Java

I made a program that checks a finished 9x9 Sudoku puzzle to see if it is correct. 我编写了一个程序来检查完成的9x9 Sudoku拼图,看是否正确。 My program works fine, however, I want to learn how to use threads. 我的程序运行正常,但是,我想学习如何使用线程。 I want a single thread to check every row, a single thread to check every column, and then a single thread to check each block. 我希望有一个线程检查每一行,有一个线程检查每一列,然后有一个线程检查每个块。 Three threads in total. 总共三个线程。 I'm having trouble converting my code to do this correctly without getting errors. 我在转换代码以正确执行此操作而又没有出错时遇到了麻烦。 My code is below: 我的代码如下:

public class Sudoku {

public final Runnable row;
public final Runnable col;
public final Runnable block;
public final Runnable testboard;

public Sudoku(){
    row = new Runnable(){
      public void run(){
           Sudoku.this.testRows(board);
        }
    };
    col = new Runnable(){
        public void run(){
            Sudoku.this.testCols(board);
        }
    };
    block = new Runnable(){
        public void run(){
            Sudoku.this.testRegions(board);
        }
    };
    testboard = new Runnable(){
        public void run(){
            Sudoku.this.testBoard(board);
        }
    };
}

public boolean testBoard(int[][] board) {
    if (!testSize(board)) {
        return false;
    }
    if (!testRows(board)) {
        return false;
    }
    if (!testCols(board)) {
        return false;
    }
    if (!testRegions(board)) {
        return false;
    }
    return true;
}

boolean testSize(int[][] board) {
    if (board.length != 9) {
        return false;
    }
    for (int i = 0; i < board.length; i++) {
        if (board[i].length != 9) {
            return false;
        } else;
    }
    return true;
}

boolean checkDigits(int[] array) {
    if (array.length != 9) {
        return false;
    }
    int[] counts = new int[10];
    for (int i = 0; i
            < array.length; i++) {

        if (array[i] < 1 || array[i] > 9) {
            return false;
        }
        if (counts[array[i]] > 0) {
            return false;
        }
        counts[array[i]]++;
    }
    return true;
}

boolean testRows(int[][] board) {
    for (int i = 0; i < board.length; i++) {
        if (!checkDigits(board[i])) {
            return false;
        }
    }
    return true;
}

boolean testCols(int[][] board) {
    int[] tmp = new int[board.length];
    for (int col = 0; col < board.length; col++) {
        for (int row = 0; row < board.length; row++) {
            tmp[row]
                    = board[row][col];
        }
        if (!checkDigits(tmp)) {
            return false;
        }
    }
    return true;
}

boolean testRegions(int[][] board) {
    for (int row = 0; row < board.length; row += 3) {
        for (int col = 0; col
                < board.length; col += 3) {
            if (!testRegion(board, row, col)) {
                return false;
            }
        }
    }
    return true;
}

boolean testRegion(int[][] board, int startRow, int startCol) {
    int[] tmp = new int[board.length];
    int index = 0;
    for (int row = startRow; row < startRow + 3; row++) {
        for (int col = startCol; col < startCol + 3; col++) {
            tmp[index]
                    = board[row][col];
            index++;
        }
    }
    return checkDigits(tmp);
}
}

public class TestPuzzle {

public static void testpuzzle() throws FileNotFoundException{
    Sudoku sudoku = new Sudoku();
    String fileName = "SudokuRight.txt";//This is for the print statment
    Scanner inputStream = null;
    String[] line;
    System.out.println("The file " + fileName + " contains the following sudoku puzzle:\n");
    inputStream = new Scanner(new File("C:\\Users\\username\\Documents\\NetBeansProjects\\Sudoku\\SudokuRight.txt"));
    int[][] puzzle = new int[9][9];
    int row = 0;
    while (inputStream.hasNextLine()) {
        line = inputStream.nextLine().split(",");
        for (int i = 0; i < 9; i++) {
            puzzle[row][i] = Integer.parseInt(line[i]);
        }
        row++;
    }
    for (int i = 0; i < 9; i++) {
        System.out.println(Arrays.toString(puzzle[i]));
    }

    boolean result = sudoku.testBoard(puzzle);
    System.out.println("Result: " + result);
    if (result == true) {
        System.out.println("This sudoku solution IS valid!");
    } else if (result == false) {
        System.out.println("This sudoku solution IS NOT valid!");
    }
}
}

Here is my main class: 这是我的主要课程:

public static void main(String[] args) throws FileNotFoundException {
    Sudoku x = new Sudoku();
    new Thread(x.row).start();
    new Thread(x.col).start();
    new Thread(x.block).start();
    new Thread(x.testboard).start();
}

Here is my file that I scan in: 这是我扫描的文件:

8,3,5,4,1,6,9,2,7
2,9,6,8,5,7,4,3,1
4,1,7,2,9,3,6,5,8
5,6,9,1,3,4,7,8,2
1,2,3,6,7,8,5,4,9
7,4,8,5,2,9,1,6,3
6,5,2,7,8,1,3,9,4
9,8,1,3,4,5,2,7,6
3,7,4,9,6,2,8,1,5

Here is my output before I tried using Threads: 这是我尝试使用线程之前的输出:

The file SudokuRight.txt contains the following sudoku puzzle:  

[8, 3, 5, 4, 1, 6, 9, 2, 7]
[2, 9, 6, 8, 5, 7, 4, 3, 1]
[4, 1, 7, 2, 9, 3, 6, 5, 8]
[5, 6, 9, 1, 3, 4, 7, 8, 2]
[1, 2, 3, 6, 7, 8, 5, 4, 9]
[7, 4, 8, 5, 2, 9, 1, 6, 3]
[6, 5, 2, 7, 8, 1, 3, 9, 4]
[9, 8, 1, 3, 4, 5, 2, 7, 6]
[3, 7, 4, 9, 6, 2, 8, 1, 5]
Result: true
This sudoku solution IS valid!
BUILD SUCCESSFUL (total time: 0 seconds)

I want my output to be the exact same as above, but I want to find a way to break my methods down into threads so that the rows, columns, and blocks all get checked concurrently. 我希望我的输出与上面的完全相同,但是我想找到一种方法将我的方法分解为线程,以便同时检查行,列和块。 Any help would be very much so appreciated. 任何帮助将不胜感激。

You can do it like this: 您可以这样做:

First create a Callable for each test you are making 首先为要进行的每个测试创建一个Callable

   Callable<Boolean> testCollumnsTask = new Callable<>(){

           @Override
           public Boolean call(){
              return Boolean.valueOf(testCols(board));
           }
    }

Which is alot easier with lambdas 使用lambdas更容易

  Callable<Boolean> callable = () -> Boolean.valueOf(testCols(board));

Do the same for the rest , replace testCols with other tests. 其余步骤相同,将testCols替换为其他测试。

Now the multithreaded testBoard (assuming you are using java 8) 现在是多线程testBoard (假设您使用的是Java 8)

public boolean testBoard(int[][] board) {
    List<Callable<Boolean>> tests = new ArrayList<>();
    tests.add(() -> Boolean.valueOf(testCols(board));
    tests.add(() -> Boolean.valueOf(testRegions(board));
    tests.add(() -> Boolean.valueOf(testRows(board));
    tests.add(() -> Boolean.valueOf(testSize(board));

    /*Maybe store this threadPool in a field so you dont create it everytime*/
    ExecutorService threadPool = Executors.newCachedThreadPool();
    List<Future<Boolean>> results = threadPool.invokeAll(tests);

    for(Future<Boolean> future: results){
       if(!Boolean.TRUE.equals(future.get()){
          return false;
       }
    }
    return true;
}

future.get() throws a checked exception which you should decide how to handle it. future.get()引发一个已检查的异常,您应决定如何处理它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM