简体   繁体   中英

Sudoku Multithreading with lambda and Callable in Java

I made a program that checks to see if a finished 9x9 Sudoku matrix is correct or not. I wanted to create threads that checked the rows, columns, and regions at the same time to see if the numbers 1-9 appeared in them. I am new to using Callable and lambda. Here is my code so far:

public class Sudoku {

    public boolean testBoard(int[][] board) throws InterruptedException, ExecutionException {
        List<Callable<Boolean>> tests = new ArrayList<>();
        tests.add(() -> testCols(board));
        tests.add(() -> testRegions(board));
        tests.add(() -> testRows(board));
        tests.add(() -> 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;
    }

    // check that the board is 9 x 9
    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;
    }

    // check that the digits 1-9 each appear exactly once in the given array
    boolean checkDigits(int[] array) {
        if (array.length != 9) {
            return false;
        }
        int[] counts = new int[10];
        for (int i = 0; i
                < array.length; i++) {
    // invalid number
            if (array[i] < 1 || array[i] > 9) {
                return false;
            }
    // we have already seen this number
            if (counts[array[i]] > 0) {
                return false;
            }
            counts[array[i]]++;
        }
        return true;
    }
    // return true if all rows are correct

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

    boolean testCols(int[][] board) {
        int[] tmp = new int[board.length];
        for (int col = 0; col < board.length; col++) {
    // fill a temp array with every element of the column
            for (int row = 0; row < board.length; row++) {
                tmp[row]
                        = board[row][col];
            }
    // check to make sure it has all the right digits
            if (!checkDigits(tmp)) {
                return false;
            }
        }
        return true;
    }
    // return true if every region is correct

    boolean testRegions(int[][] board) {
    //loop through each region, passing the indices of the upper-left corner to the next method
    //note that we increment row and column counters by 3 here
        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;
    }
    // test a specific region, given the upper left corner

    boolean testRegion(int[][] board, int startRow, int startCol) {
        int[] tmp = new int[board.length];
    // fill a temporary array with every element of the region
        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++;
            }
        }
    // check if we have all of the right digits in the region
        return checkDigits(tmp);
    }
}

public class TestPuzzle {

    public static void testpuzzle() throws FileNotFoundException, InterruptedException, ExecutionException{
        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!");
        }
    }
}

public class Main {

    //This is the main method to check the validity of sudoku puzzles
    public static void main(String[] args) throws FileNotFoundException, InterruptedException, ExecutionException {
        TestPuzzle.testpuzzle();
    }
}

Someone was trying to teach me about using callable and lambda, but I'm still slightly confused. My code does run correctly right now, however, in NetBeans after it prints out the results it continues to run until I manually terminate it. I'm not sure why? I thought I had to have a block of statements in my code like this:

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

However I'm not sure where to put these lines? I can't put them in the constructor because "board" hasn't been initialized yet. I'm sure this is an easy fix, I'm just stuck since I'm new to this. Any help please?

As per my comment, I believe your issue is that you have not called shutdown() on your executor service after adding all Callables to it and invoking them all. I suggest that you do just this:

ExecutorService threadPool = Executors.newCachedThreadPool();
List<Future<Boolean>> results = threadPool.invokeAll(tests);
threadPool.shutdown(); // ******* add this! *********

This should help shut the threadPool down once all of its Callables have completed their actions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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