View Javadoc
1   package io.github.skenvy;
2   
3   /**
4    * An individual cell in the whole grid.
5    */
6   public class Cell {
7   
8     /**
9      * The initial value that a cell starts with. 0 for empty cells.
10     */
11    private final int initialValue;
12  
13    /**
14     * The current value of a cell, whether assigned at the start, or
15     * determined through solving. 0 for empty cells.
16     */
17    private int value;
18  
19    /**
20     * An array to track the possibilities for an individual cell. 
21     */
22    private final boolean[] possibleValues;
23  
24    /**
25     * The row that this cell is a member of.
26     */
27    private CellCollection row;
28  
29    /**
30     * The column that this cell is a member of.
31     */
32    private CellCollection column;
33  
34    /**
35     * The box that this cell is a member of.
36     */
37    private CellCollection box;
38  
39    /**
40     * Initialise an empty cell for a standard sudoku board of size 3*3*3*3.
41     */
42    public Cell() {
43      this.initialValue = 0;
44      this.value = 0;
45      this.possibleValues = initialisePossibleValues(3);
46    }
47  
48    /**
49     * Initialise a non-empty cell for a standard sudoku board of size 3*3*3*3.
50     *
51     * @param initialValue is used to provide an initial value.
52     * @throws SudokuCellInvalidInitialValueException when attempting to create a
53     *     new Cell with an invalid value
54     */
55    public Cell(int initialValue) throws SudokuCellInvalidInitialValueException {
56      this.initialValue = initialValue;
57      this.value = initialValue;
58      this.possibleValues = initialisePossibleValues(3);
59      if (initialValue < 0 || initialValue > 9) {
60        throw new SudokuCellInvalidInitialValueException(initialValue, 3);
61      }
62    }
63  
64    /**
65     * Initialise a non-empty cell for a sudoku board of arbitrary size.
66     *
67     * @param initialValue is used to provide an initial value.
68     * @param boardSize is used to specify a row / column length other than 9.
69     * @throws SudokuCellInvalidInitialValueException when attempting to create a
70     *     new Cell with an invalid value
71     */
72    public Cell(int initialValue, int boardSize) throws SudokuCellInvalidInitialValueException {
73      this.initialValue = initialValue;
74      this.value = initialValue;
75      this.possibleValues = initialisePossibleValues(boardSize);
76      if (initialValue < 0 || initialValue > (boardSize * boardSize)) {
77        throw new SudokuCellInvalidInitialValueException(initialValue, boardSize);
78      }
79    }
80  
81    /**
82     * Initialise a non-empty cell for a sudoku board of arbitrary size.
83     *
84     * @param initialValue is used to provide an initial value.
85     * @param boardSize is used to specify a row / column length other than 9.
86     * @throws SudokuCellInvalidInitialValueException when attempting to create a
87     *     new Cell with an invalid value
88     */
89    public Cell(int initialValue, int boardSize, CellCollection row, CellCollection column, CellCollection box) throws SudokuCellInvalidInitialValueException {
90      this.initialValue = initialValue;
91      this.value = initialValue;
92      this.possibleValues = initialisePossibleValues(boardSize);
93      if (initialValue < 0 || initialValue > (boardSize * boardSize)) {
94        throw new SudokuCellInvalidInitialValueException(initialValue, boardSize);
95      }
96      this.row = row;
97      this.column = column;
98      this.box = box;
99    }
100 
101   public int getValue() {
102     return this.value;
103   }
104 
105   public void setValue(int value) throws SudokuCellCantSetValueOfPredeterminedCellException {
106     if (this.wasCellPredetermined()) {
107       throw new SudokuCellCantSetValueOfPredeterminedCellException();
108     }
109     this.value = value;
110   }
111 
112   /**
113    * True if the cell was not originally blank.
114    */
115   boolean wasCellPredetermined() {
116     return (this.initialValue != 0);
117   }
118 
119   /**
120    * True if the cell is not currently blank.
121    */
122   boolean isCellFilled() {
123     return (this.value != 0);
124   }
125 
126   boolean[] initialisePossibleValues(int boardSize) {
127     boolean[] possibilities = new boolean[(boardSize * boardSize)];
128     for (int i = 0; i < (boardSize * boardSize); i++) {
129       possibilities[i] = true;
130     }
131     return possibilities;
132   }
133 
134   /**
135    * Used for cell related exceptions.
136    */
137   public class SudokuCellException extends Exception {
138     public SudokuCellException(String string) {
139       super(string);
140     }
141   }
142 
143   public final class SudokuCellInvalidInitialValueException extends SudokuCellException {
144     public SudokuCellInvalidInitialValueException(int initialValue, int boardSize) {
145       super("Invalid initial value. Board size of " + boardSize + " allows for values from 1 to " + ((boardSize * boardSize)) + "; was given initial value of " + initialValue);
146     }
147   }
148 
149   public class SudokuCellCantSetValueOfPredeterminedCellException extends SudokuCellException {
150     public SudokuCellCantSetValueOfPredeterminedCellException() {
151       super("You cannot change the value of a predetermined cell.");
152     }
153   }
154 }