Java 中的多线程数独谜题

Multithreading Sudoku Puzzle in Java

我制作了一个程序来检查已完成的 9x9 数独游戏是否正确。我的程序运行良好,但是,我想学习如何使用线程。我想要一个线程检查每一行,一个线程检查每一列,然后一个线程检查每个块。总共三个线程。我在转换我的代码以正确执行此操作而不会出错时遇到问题。我的代码如下:

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!");
    }
}
}

这是我的主要 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();
}

这是我扫描的文件:

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

这是我尝试使用线程之前的输出:

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)

我希望我的输出与上面完全相同,但我想找到一种方法将我的方法分解为线程,以便同时检查行、列和块。任何帮助将不胜感激。

你可以这样做:

首先为您正在进行的每个测试创建一个 Callable

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

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

使用 lambda 更容易

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

对其余部分执行相同的操作,将 testCols 替换为其他测试。

现在多线程测试板(假设你用的是java8)

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() 抛出一个已检查的异常,您应该决定如何处理它。