Android Open Source - SudokuSolver Sudoku Solver Optimised






From Project

Back to project page SudokuSolver.

License

The source code is released under:

License JSON Sudoku Solver is covered under the Creative Commons Attribution 3.0 Unported License http://creativecommons.org/licenses/by/3.0/ Credits Sudoku Solver Java implementation: Kevin Coulombe...

If you think the Android project SudokuSolver listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * JSON Sudoku solver is covered under the Creative Commons Attribution 3.0 Unported License
 * http://creativecommons.org/licenses/by/3.0/
 * //from   w ww .j  a  v  a2s. c  o m
 * @author: Kevin Coulombe {@link http://www.byteauthor.com/2010/08/sudoku-solver-update/}
 */
package com.musevisions.android.SudokuSolver;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;

public class SudokuSolverOptimised {

    // -----
    // INNER TYPES
    // -----
    
    private final static class FileFormatException extends Exception {

        /**
         * 
         */
        private static final long serialVersionUID = -6708704362775269448L;
    }

    // -----
    // CONSTANTS
    // -----
    
    private final static int[] allowedBitFields = new int[] {
            0,
            1,
            1 << 1,
            1 << 2,
            1 << 3,
            1 << 4,
            1 << 5,
            1 << 6,
            1 << 7,
            1 << 8,
    };
    
    private final static int allAllowed = arraySum(allowedBitFields);

    // -----
    // STATIC METHODS
    // -----
    
    /**
     * @param args
     */
    public static final void main(String[] args) {
        // a dummy board solve to force the JIT compiler to precompile everything. (much faster)
        solveBoard(new int[][] { 
                new int[] {0,0,0,0,0,0,0,0,0},
                new int[] {0,0,0,0,0,0,0,0,0},
                new int[] {0,0,0,0,0,0,0,0,0},
                new int[] {0,0,0,0,0,0,0,0,0},
                new int[] {0,0,0,0,0,0,0,0,0},
                new int[] {0,0,0,0,0,0,0,0,0},
                new int[] {0,0,0,0,0,0,0,0,0},
                new int[] {0,0,0,0,0,0,0,0,0},
                new int[] {0,0,0,0,0,0,0,0,0}});
        
        // A delay to allow JIT compilation to run.
        try {
      Thread.sleep(1000);
    } catch (InterruptedException e1) {
      e1.printStackTrace();
    }
        
        if (args.length > 0) {
            try {
                final int[][] board = readBoard(new File(args[0]));
                
                final long timeBefore = System.nanoTime();

                final int placedNumbers = solveBoard(board);
                
                final long timeAfter = System.nanoTime();
                
                if (placedNumbers == 81) {
                    System.out.println("La r?solution a dur? " + ((timeAfter - timeBefore) / 1) + " nanoseconds.");
                }
                else {
                    System.out.println("La r?solution est impossible. L'op?ration a dur? " + ((timeAfter - timeBefore) / 100) + " nanoseconds.");
                }
                
                printBoard(board);
            } 
            catch (final FileFormatException e) {
                System.out.println("Le fichier est d'un format incorrect.");
            } 
            catch (final IOException e) {
                System.out.println("Une erreur s'est produite lors de la lecture du fichier.");
            }
        }
        else {
            System.out.println("Vous devez fournir le chemin du fichier contenant le probl?me.");
        }
    }

    public final static int solveBoard(final int[][] board) {
        final int[][] allowedValues = new int[9][9];
        int placedNumberCount = 0;
        
        for (int[] allowedValuesRow : allowedValues) {
            Arrays.fill(allowedValuesRow, allAllowed);
        }
        
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                if (board[x][y] > 0) {
                    allowedValues[x][y] = 0;
                    applyAllowedValuesMask(board, allowedValues, x, y);
                    placedNumberCount++;
                }
            }
        }
        

        return solveBoard(board, allowedValues, placedNumberCount);
    }

    private final static int solveBoard(final int[][] board, final int[][] allowedValues, int placedNumberCount) {
      
        int lastPlacedNumbersCount = 0;
      
        while (placedNumberCount - lastPlacedNumbersCount > 3 && placedNumberCount < 68 && placedNumberCount > 10) {
            lastPlacedNumbersCount = placedNumberCount;
            placedNumberCount += moveNothingElseAllowed(board, allowedValues);
            placedNumberCount += moveNoOtherRowOrColumnAllowed(board, allowedValues);
            placedNumberCount += moveNothingElseAllowed(board, allowedValues);
            
            if (placedNumberCount < 35) {
                applyNakedPairs(allowedValues);
                applyLineCandidateConstraints(allowedValues);
            }
        }
      
        if (placedNumberCount < 81) {
            final int[][] bruteForcedBoard = attemptBruteForce(board, allowedValues, placedNumberCount);

            if (bruteForcedBoard != null) {
                placedNumberCount = 0;
                
                for (int x = 0; x < 9; x++) {
                    for (int y = 0; y < 9; y++) {
                        board[x][y] = bruteForcedBoard[x][y];
                        
                        if (bruteForcedBoard[x][y] > 0) {
                            placedNumberCount++;
                        }
                    }
                }
            }
        }
        
        return placedNumberCount;
    }

    private final static int[][] attemptBruteForce(final int[][] board, final int[][] allowedValues, final int placedNumberCount) {

        for (int x = 0; x < 9; x++) {
            final int[] allowedValuesRow = allowedValues[x];
            final int[] boardRow = board[x];
            
            for (int y = 0; y < 9; y++) {
                if (boardRow[y] == 0) {
                    for (int value = 1; value <= 9; value++) {
                        if ((allowedValuesRow[y] & allowedBitFields[value]) > 0) {
                            final int[][] testBoard = copyGameMatrix(board);
                            final int[][] testAllowedValues = copyGameMatrix(allowedValues);
                            setValue(testBoard, testAllowedValues, value, x, y);
                            
                            final int placedNumbers = solveBoard(testBoard, testAllowedValues, placedNumberCount + 1);
                            
                            if (placedNumbers == 81) {
                                return testBoard;
                            }
                        }
                    }
                    
                    return null;
                }
            }
        }
        
        return null;
    }

    private final static int moveNoOtherRowOrColumnAllowed(final int[][] board, final int[][] allowedValues) {
        
        int moveCount = 0;
        
        for (int value = 1; value <= 9; value++) {
            final int allowedBitField = allowedBitFields[value];
            
            for (int x = 0; x < 9; x++) {
                int allowedY = -1;
                final int[] allowedValuesRow = allowedValues[x];
                
                for (int y = 0; y < 9; y++) {
                    if ((allowedValuesRow[y] & allowedBitField) > 0) {
                        if (allowedY < 0) {
                            allowedY = y;
                        }
                        else {
                            allowedY = -1;
                            break;
                        }
                    }
                }
                
                if (allowedY >= 0) {
                    setValue(board, allowedValues, value, x, allowedY);
                    moveCount++;
                }
            }
            
            for (int y = 0; y < 9; y++) {
                int allowedX = -1;
                
                for (int x = 0; x < 9; x++) {
                    if ((allowedValues[x][y] & allowedBitField) > 0) {
                        if (allowedX < 0) {
                            allowedX = x;
                        }
                        else {
                            allowedX = -1;
                            break;
                        }
                    }
                }
                
                if (allowedX >= 0) {
                    setValue(board, allowedValues, value, allowedX, y);
                    moveCount++;
                }
            }
        }

        return moveCount;
    }

    private final static int moveNothingElseAllowed(final int[][] board,
            final int[][] allowedValues) {
        
        int moveCount = 0;
        
        for (int x = 0; x < 9; x++) {
            final int[] allowedValuesRow = allowedValues[x];
            
            for (int y = 0; y < 9; y++) {
                final int currentAllowedValues = allowedValuesRow[y];
                if (countSetBits(currentAllowedValues) == 1) {
                    setValue(board, allowedValues, getLastSetBitIndex(currentAllowedValues), x, y);
                    moveCount++;
                }
            }
        }

        return moveCount;
    }

    private final static void applyNakedPairs(final int[][] allowedValues) {
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                final int value = allowedValues[x][y];
                
                if (countSetBits(value) == 2) {
                    for (int scanningY = y + 1; scanningY < 9; scanningY++) {
                        if (allowedValues[x][scanningY] == value) {
                            final int removeMask = ~value;
                            
                            for (int applyY = 0; applyY < 9; applyY++) {
                                if (applyY != y && applyY != scanningY) {
                                    allowedValues[x][applyY] &= removeMask;
                                }
                            }
                        }
                    }
                }
            }
        }
        
        for (int y = 0; y < 9; y++) {
            for (int x = 0; x < 9; x++) {
                final int value = allowedValues[x][y];
                
                if (value != 0 && countSetBits(value) == 2) {
                    for (int scanningX = x + 1; scanningX < 9; scanningX++) {
                        if (allowedValues[scanningX][y] == value) {
                            final int removeMask = ~value;
                            
                            for (int applyX = 0; applyX < 9; applyX++) {
                                if (applyX != x && applyX != scanningX) {
                                    allowedValues[applyX][y] &= removeMask;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private final static void applyLineCandidateConstraints(final int[][] allowedValues) {
        for (int value = 1; value <= 9; value++) {
            final int valueMask = allowedBitFields[value];
            final int valueRemoveMask = ~valueMask;
            final int[] sectionAvailabilityColumn = new int[9];
            
            for (int x = 0; x < 9; x++) {
                final int finalX = x;
                
                for (int y = 0; y < 9; y++) {
                    if ((allowedValues[finalX][y] & valueMask) != 0) {
                        sectionAvailabilityColumn[finalX] |= (1 << (y / 3));
                    }
                }
                
                if (finalX == 2 || finalX == 5 || finalX == 8) {
                    for (int scanningX = finalX - 2; scanningX <= finalX; scanningX++) {
                        final int bitCount = countSetBits(sectionAvailabilityColumn[scanningX]);
                        
                        if (bitCount == 1) {
                            for (int applyX = finalX - 2; applyX <= finalX; applyX++) {
                                if (scanningX != applyX) {
                                    for (int applySectionY = 0; applySectionY < 3; applySectionY++) {
                                        if ((sectionAvailabilityColumn[scanningX] & (1 << applySectionY)) != 0) {
                                            for (int applyY = applySectionY * 3; applyY < (applySectionY + 1) * 3; applyY++) {
                                                allowedValues[applyX][applyY] &= valueRemoveMask;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        
                        if (bitCount == 2 && scanningX < finalX) {
                            for (int scanningSecondPairX = scanningX + 1; scanningSecondPairX <= finalX; scanningSecondPairX++) {
                                if (sectionAvailabilityColumn[scanningX] == sectionAvailabilityColumn[scanningSecondPairX]) {
                                    final int applyX;
                                    
                                    if (scanningSecondPairX != finalX) {
                                        applyX = finalX;
                                    }
                                    else if (scanningSecondPairX - scanningX > 1) {
                                        applyX = scanningSecondPairX - 1;
                                    }
                                    else {
                                        applyX = scanningX - 1;
                                    }
                                    
                                    for (int applySectionY = 0; applySectionY < 3; applySectionY++) {
                                        if ((sectionAvailabilityColumn[scanningX] & (1 << applySectionY)) != 0) {
                                            for (int applyY = applySectionY * 3; applyY < (applySectionY + 1) * 3; applyY++) {
                                                allowedValues[applyX][applyY] &= valueRemoveMask;
                                            }
                                        }
                                    }
                                    
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            
            final int[] sectionAvailabilityRow = new int[9];
            
            for (int y = 0; y < 9; y++) {
                final int finalY = y;
                
                for (int x = 0; x < 9; x++) {
                    if ((allowedValues[x][finalY] & valueMask) != 0) {
                        sectionAvailabilityRow[finalY] |= (1 << (x / 3));
                    }
                }
                
                if (finalY == 2 || finalY == 5 || finalY == 8) {
                    for (int scanningY = finalY - 2; scanningY <= finalY; scanningY++) {
                        final int bitCount = countSetBits(sectionAvailabilityRow[scanningY]);
                        
                        if (bitCount == 1) {
                            for (int applyY = finalY - 2; applyY <= finalY; applyY++) {
                                if (scanningY != applyY) {
                                    for (int applySectionX = 0; applySectionX < 3; applySectionX++) {
                                        if ((sectionAvailabilityRow[scanningY] & (1 << applySectionX)) != 0) {
                                            for (int applyX = applySectionX * 3; applyX < (applySectionX + 1) * 3; applyX++) {
                                                allowedValues[applyX][applyY] &= valueRemoveMask;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        
                        if (bitCount == 2 && scanningY < finalY) {
                            for (int scanningSecondPairY = scanningY + 1; scanningSecondPairY <= finalY; scanningSecondPairY++) {
                                if (sectionAvailabilityRow[scanningY] == sectionAvailabilityRow[scanningSecondPairY]) {
                                    final int applyY;
                                    
                                    if (scanningSecondPairY != finalY) {
                                        applyY = finalY;
                                    }
                                    else if (scanningSecondPairY - scanningY > 1) {
                                        applyY = scanningSecondPairY - 1;
                                    }
                                    else {
                                        applyY = scanningY - 1;
                                    }
                                    
                                    for (int applySectionX = 0; applySectionX < 3; applySectionX++) {
                                        if ((sectionAvailabilityRow[scanningY] & (1 << applySectionX)) != 0) {
                                            for (int applyX = applySectionX * 3; applyX < (applySectionX + 1) * 3; applyX++) {
                                                allowedValues[applyX][applyY] &= valueRemoveMask;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private final static void setValue(final int[][] board, final int[][] allowedValues, final int value, final int x, final int y) {
        board[x][y] = value;
        allowedValues[x][y] = 0;
        applyAllowedValuesMask(board, allowedValues, x, y);
    }
    
    private final static int getLastSetBitIndex(int value) {
        int bitIndex = 0;
        
        while (value > 0) {
            bitIndex++;
            value >>= 1;
        }
        
        return bitIndex;
    }

    private final static void applyAllowedValuesMask(final int[][] board,
            final int[][] allowedValues, final int x, final int y) {

        final int mask = ~allowedBitFields[board[x][y]];
        
        for (int maskApplyX = 0; maskApplyX < 9; maskApplyX++) {
            allowedValues[maskApplyX][y] &= mask;
        }
        
        final int[] allowedValuesRow = allowedValues[x];
        
        for (int maskApplyY = 0; maskApplyY < 9; maskApplyY++) {
            allowedValuesRow[maskApplyY] &= mask;
        }
        
        int sectionX1 = 0;
        int sectionX2 = 0;
        
        switch (x) {
            case 0:
                sectionX1 = x + 1;
                sectionX2 = x + 2;
                break;
            case 1:
                sectionX1 = x - 1;
                sectionX2 = x + 1;
                break;
            case 2:
                sectionX1 = x - 2;
                sectionX2 = x - 1;
                break;
            case 3:
                sectionX1 = x + 1;
                sectionX2 = x + 2;
                break;
            case 4:
                sectionX1 = x - 1;
                sectionX2 = x + 1;
                break;
            case 5:
                sectionX1 = x - 2;
                sectionX2 = x - 1;
                break;
            case 6:
                sectionX1 = x + 1;
                sectionX2 = x + 2;
                break;
            case 7:
                sectionX1 = x - 1;
                sectionX2 = x + 1;
                break;
            case 8:
                sectionX1 = x - 2;
                sectionX2 = x - 1;
                break;
                
        }

        int sectionY1 = 0;
        int sectionY2 = 0;
        
        switch (y) {
            case 0:
                sectionY1 = y + 1;
                sectionY2 = y + 2;
                break;
            case 1:
                sectionY1 = y - 1;
                sectionY2 = y + 1;
                break;
            case 2:
                sectionY1 = y - 2;
                sectionY2 = y - 1;
                break;
            case 3:
                sectionY1 = y + 1;
                sectionY2 = y + 2;
                break;
            case 4:
                sectionY1 = y - 1;
                sectionY2 = y + 1;
                break;
            case 5:
                sectionY1 = y - 2;
                sectionY2 = y - 1;
                break;
            case 6:
                sectionY1 = y + 1;
                sectionY2 = y + 2;
                break;
            case 7:
                sectionY1 = y - 1;
                sectionY2 = y + 1;
                break;
            case 8:
                sectionY1 = y - 2;
                sectionY2 = y - 1;
                break;
        }
        
        final int[] allowedValuesRow1 = allowedValues[sectionX1];
        final int[] allowedValuesRow2 = allowedValues[sectionX2];
        
        allowedValuesRow1[sectionY1] &= mask;
        allowedValuesRow1[sectionY2] &= mask;
        allowedValuesRow2[sectionY1] &= mask;
        allowedValuesRow2[sectionY2] &= mask;
    }

    private final static int countSetBits(int value) {
        int count = 0;
        
        while (value > 0) {
            value = value & (value - 1);
            count++;
        }
        
        return count;
    }

    private final static int arraySum(final int[] array) {
        int sum = 0;
        
        for (int value : array) {
            sum += value;
        }
        
        return sum;
    }

    private final static int[][] copyGameMatrix(final int[][] matrix) {
        return new int[][] {
            Arrays.copyOf(matrix[0], 9),
            Arrays.copyOf(matrix[1], 9),
            Arrays.copyOf(matrix[2], 9),
            Arrays.copyOf(matrix[3], 9),
            Arrays.copyOf(matrix[4], 9),
            Arrays.copyOf(matrix[5], 9),
            Arrays.copyOf(matrix[6], 9),
            Arrays.copyOf(matrix[7], 9),
            Arrays.copyOf(matrix[8], 9),
        };
    }

    private final static void printBoard(final int[][] board) {
        for (int y = 0; y < 9; y++) {
            for (int x = 0; x < 9; x++) {
                System.out.print(board[x][y]);
            }
            
            System.out.println();
        }
    }

    private final static int[][] readBoard(final File file) throws FileFormatException, IOException {
        final int[][] board = new int[9][9];
        final BufferedReader input =  new BufferedReader(new FileReader(file));

        try {
            String line = null; //not declared within while loop
            int lineIndex = 0;
            
            while (( line = input.readLine()) != null) {
                if (line.length() != 9 || lineIndex > 8) {
                    throw new FileFormatException();
                }
            
                for (int letterIndex = 0; letterIndex < 9; letterIndex++) {
                    final int value = Character.getNumericValue(line.charAt(letterIndex));
                    
                    if (value < 0 || value > 9) {
                        throw new FileFormatException();
                    }
                    
                    board[letterIndex][lineIndex] = value;
                }
                
                lineIndex++;
            }
            
            if (lineIndex != 9) {
                throw new FileFormatException();
            }
        }
        finally {
            input.close();
        }
        
        return board;
    }
}




Java Source Code List

com.musevisions.android.SudokuSolver.CustomDialogs.java
com.musevisions.android.SudokuSolver.GridView.java
com.musevisions.android.SudokuSolver.HttpPostUtils.java
com.musevisions.android.SudokuSolver.JSONHelper.java
com.musevisions.android.SudokuSolver.MainTabActivity.java
com.musevisions.android.SudokuSolver.StoreHelper.java
com.musevisions.android.SudokuSolver.SudokuCore.java
com.musevisions.android.SudokuSolver.SudokuLoaderActivity.java
com.musevisions.android.SudokuSolver.SudokuRetrieverTask.java
com.musevisions.android.SudokuSolver.SudokuRetriever.java
com.musevisions.android.SudokuSolver.SudokuSolverActivity.java
com.musevisions.android.SudokuSolver.SudokuSolverBruteForce.java
com.musevisions.android.SudokuSolver.SudokuSolverOptimised.java
com.musevisions.android.SudokuSolver.SudokuSolverTask.java