import java.io.*; import java.util.Scanner; public class Sudoku { public static final int SIZE = 9; private int[][] grid; /** Make an empty grid */ public Sudoku() { grid = new int[SIZE][SIZE]; } /** Read the puzzle from a file @param filename the name of the external text file */ public void read(String filename) throws IOException { Scanner infile = new Scanner(new FileReader(filename)); // read in the file contents for (int row = 0; row < SIZE; row++) { for (int col = 0; col < SIZE; col++) { grid[row][col] = infile.nextInt(); } } } /** print out the grid for reference */ public void print() { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { System.out.print(grid[i][j]); if (j % 3 == 2 && j != SIZE-1) System.out.print('|'); } System.out.println(); if (i % 3 == 2 && i != SIZE-1) System.out.println("---+---+---"); } System.out.println(); } /** Helper method for validating a sudoku grid @return true if a valid solution, false if not */ public boolean validate() { boolean result = true; String invalids = ""; if (!goodRows()) result = false; if (!goodColumns()) result = false; if (!goodBoxes()) result = false; return result; } /** Helper method for validating a 1D array of ints @param seg the array to validate @return true if the array contains all the integers between 1 and length, inclusive, false otherwise. */ private static boolean testSegment(int[] seg) { // create an array of flag variables to see if each number 1-9 // occurs in the seg array boolean[] found = new boolean[SIZE]; // automatically initialized to all false // Print each section if you're curious // for (int j = 0; j < SIZE; j++) { // System.out.print(seg[j]); // } // System.out.println(); for (int i = 0; i < seg.length; i++) { if (seg[i] > SIZE || seg[i] < 1) // to prevent out of bounds errors return false; else found[seg[i]-1] = true; } for (int i = 0; i < found.length; i++) { // see if all found if (! found[i]) // missing number i+1 return false; } // If it makes it this far, it's valid return true; } /** Test all rows, display invalid ones on screen @return true if all rows good, false otherwise */ public boolean goodRows() { String invalids = ""; boolean result = true; for (int i = 0; i < SIZE; i++) { if (!testSegment(grid[i])) { invalids += (i+1) + " "; result = false; } } if (invalids.length() != 0) System.out.println("invalid rows: " + invalids); return result; } /** Test all columns - copy each to temp 1D array to call test method, display invalid ones on screen @return true if all good, false otherwise */ public boolean goodColumns() { boolean result = true; String invalids = ""; int[] temp = new int[SIZE]; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { temp[j] = grid[j][i]; } if (!testSegment(temp)) { invalids += (i+1) + " "; result = false; } } if (invalids.length() != 0) System.out.println("invalid columns: " + invalids); return result; } /** Test all subgrids - copy each to 1D array for test method See end of program for explanation of subgrid numbers and starting values Display invalid boxes on screen @return true if all good, false otherwise */ public boolean goodBoxes() { boolean result = true; String invalids = ""; int[] temp = new int[SIZE]; int rowstart, colstart; for (int i=0; i < SIZE; i++) { rowstart = 3 * (i/3); colstart = 3 * (i%3); int index = 0; for (int r=rowstart; r < rowstart+3; r++) for (int c=colstart; c < colstart+3; c++) { temp[index++] = grid[r][c]; } if (!testSegment(temp)) { invalids += (i+1) + " "; result = false; } } if (invalids.length() != 0) System.out.println("invalid cubes: " + invalids); return result; } } // class /**************************************** Cube Numbers in double array: x x x x x x x x x x 0 x x 1 x x 2 x x x x x x x x x x x x x x x x x x x x 3 x x 4 x x 5 x x x x x x x x x x x x x x x x x x x x 6 x x 7 x x 8 x x x x x x x x x x Starting rows: 0 for cubes 0, 1, 2 3 for cubes 3, 4, 5 6 for cubes 6, 7, 8 Starting col: 0 for cubes 0, 3, 6 3 for cubes 1, 4, 7 6 for cubes 2, 5, 8 *****************************************/