sudoku v1.0.1 Sudoku.Strategy
Routines to implement algorithmic solving of Sudoku puzzles. See: http://www.stolaf.edu/people/hansonr/sudoku/12rules.htm
Essentially all rules boil down to:
- naked singles
- hidden singles 3,4. locked candidates
- naked tuples
- hidden tuples
- grid analysis (X-wings, Swordfish, etc.)
Summary
Functions
Apply inferences to board. This is the process of taking a given inference and a board structure and updating the board to show the implications of the inference
Find all combinations of size ‘num’ from the list ‘to_pick_from’
Find eliminations through Grid Analysis
Guess at a candidate to eliminate from a square
Find hidden singles
Find locked candidates
Find naked singles
Find naked tuples (and hidden tuples)
Examine a sudoku board and return either:
- {:invalid, true} - (ie no candidates left for a given square and no backtracking opportunity)
- {:backtrack, :contradition} - implies we must have a backtracking option, but we have reached an invalid board state
- {:solved, true} - (ie all squares have a solution)
- An inference rule which allows one or more eliminations to take place
- A guess - no rule based inferences can be found, so make a guess *
Many strategies generate inferences that whilst true, may not advance the solution
Entry point to solve a sudoku board
Advance the board by one inference step (including guessing)
Iteratively compute a next inference to advance the board (including guessing) and then apply that inference to advance the board state
Functions
Apply inferences to board. This is the process of taking a given inference and a board structure and updating the board to show the implications of the inference.
Note: This may leave to an invalid board (so always check it’s valid after applying any inference)
We understand the following inference rules:
- :naked_singles
- :hidden_singles
- :locked_candidates
- :naked_tuples
- :grid_analysis
- :guess
and also the backtrack inference which simply returns the board to the previous state
- :backtrack
Find eliminations through Grid Analysis
Formally:
7. grid analysis (X-Wings, Swordfish, etc.)
‘’’ 7r. (r_n ^ c_n ^ k) ^ !(r_n ^ !c_n ^ k) —> !(!r_n ^ c_n ^ k) 7c. (r_n ^ c_n ^ k) ^ !(!r_n ^ c_n ^ k) —> !(r_n ^ !c_n ^ k) ‘’’
(7r) says, “If a candidate k is possible in the intersection of n rows and n columns but is not possible elsewhere in those n rows, then it is also not possible elsewhere in those n columns.”
(7c) says the same, but reversing rows and columns.
Guess at a candidate to eliminate from a square.
Considered a last ditch strategy, elimination through constraints is considered more elegant. Strategy is simply to select the square with the least candidates remaining.
Find locked candidates
A locked candidate is where there exists a box with two/three candidates in a row/col. a) If they don’t exist elsewhere on the row, then they cannot be elsewhere in the box b) If they don’t exist elsewhere in the box, then they cannot be elsewhere on the row/col
Intuitively: a) If the candidate were elsewhere in the box, it could therefore not be in this row/col, hence we would have a contradiction because it would now not be possible anywhere on that row/col
b) If the candidate were elsewhere in the row/col, it could therefore not be in this box, hence we would have a contradiction because it would now not be possible anywhere in this box
Formally
3. locked candidates, type 1:
3r. (r ^ b ^ k) ^ !(r ^ !b ^ k) --> !(!r ^ b ^ k)
3c. (c ^ b ^ k) ^ !(c ^ !b ^ k) --> !(!c ^ b ^ k)
(3r) says, “If a candidate k is possible in a certain intersection of row and block but is not possible elsewhere in that row, then it is also not possible elsewhere in that block.”
(3c) says the same for columns.
4. locked candidates, type 2:
4r. (r ^ b ^ k) ^ !(!r ^ b ^ k) --> !(r ^ !b ^ k)
4c. (c ^ b ^ k) ^ !(!c ^ b ^ k) --> !(c ^ !b ^ k)
(4r) says, “If a candidate k is possible in a certain intersection of row and block but is not possible elsewhere in that block, then it is also not possible elsewhere in that row.”
(4c) says the same, but for columns.
This basic logic generalizes to ALL of the standard types of analysis. Here X_n means a “exactly n of X”, where X=r is row, X=c is column, and X=k is candidate.
Find naked singles
A naked symbol is where there is only a single candidate option for a given square Essentially this is a formal assignment of this option to this square
Formally
1. naked singles:
1r. (r ^ c ^ k) ^ !(r ^ c ^ !k) --> !(r ^ !c ^ k)
1c. (r ^ c ^ k) ^ !(r ^ c ^ !k) --> !(!r ^ c ^ k)
1b. (b ^ (r ^ c) ^ k) ^ !(b ^ (r ^ c) ^ !k) --> !(b ^ !(r ^ c) ^ k)
(1r) says, “If a candidate k is possible in a certain intersection of row and column (i.e., a cell), and no other candidates are possible in that cell, then k is not possible elsewhere in that row.”
(1c) says the same for “that column.”
(1b) says the same for “that block.”
Find naked tuples (and hidden tuples)
A naked tuple is where there are only N choices for N squares in some unit. These choices must therefore belong only within these N squares and so can be removed from all other squares within the rest of the unit
Note: some choices might only be valid in some squares.
Intuitively we can see that if there are only N (total) choices for N squares, then those choices cannot exist elsewhere, if they did we would have N-1 choices for N squares
Note: Hidden tuples are simply the reverse of naked tuples, ie a hidden pair is simply a naked tuple of order N-2
Formally:
5. naked tuples (includes Rules 1r, 1c, and 1b):
5r. (r ^ c_n ^ k_n) ^ !(r ^ c_n ^ !k_n) --> !(r ^ !c_n ^ k_n)
5c. (c ^ r_n ^ k_n) ^ !(c ^ r_n ^ !k_n) --> !(c ^ !r_n ^ k_n)
5b. (b ^ (r ^ c)_n ^ k_n) ^ !(b ^ (r ^ c)_n ^ !k_n) --> !(b ^ !(r ^ c)_n ^ k_n)
(5r) says, “If n candidates are possible in a set of n columns of a given row, and no other candidates are possible and in those n cells, then those n candidates are not possible elsewhere in that row.”
(5c) says the same for columns. (3b) says the same for blocks.
6. hidden tuples (includes Rules 2r, 2c, and 2b):
6r. (r ^ c_n ^ k_n) ^ !(r ^ !c_n ^ k_n) --> !(r ^ c_n ^ !k_n)
6c. (c ^ r_n ^ k_n) ^ !(c ^ !r_n ^ k_n) --> !(c ^ r_n ^ !k_n)
6b. (b ^ (r ^ c)_n ^ k_n) ^ !(b ^ !(r ^ c)_n ^ k_n) --> !(b ^ (r ^ c)_n ^ !k_n)
(6r) says, “If n candidates are possible in a set of n columns of a given row, and those n candidates are not possible elsewhere in that row, then no other candidates are possible in those n cells.”
(6c) says the same for columns. (6b) says the same for blocks.
Note that exchanging k_n and !k_n and exchanging c_n and !c_n in 6r gives an alternative statement of 5r:
5r’. (r ^ !c_n ^ !k_n) ^ !(r ^ c_n ^ !k_n) —> !(r ^ !c_n ^ k_n)
This says: “If other than n candidates are possible in other than n cells of a row, and those other candidates are not possible in this set of n cells, then this set of n candidates is not possible in those other cells. (5r) says the same thing, but in a simpler fashion. What this exchanging shows is that naked tuples are the same as hidden tuples, just seen from different perspectives.
Examine a sudoku board and return either:
- {:invalid, true} - (ie no candidates left for a given square and no backtracking opportunity)
- {:backtrack, :contradition} - implies we must have a backtracking option, but we have reached an invalid board state
- {:solved, true} - (ie all squares have a solution)
- An inference rule which allows one or more eliminations to take place
- A guess - no rule based inferences can be found, so make a guess *
Many strategies generate inferences that whilst true, may not advance the solution
Here we filter out any inferences which don’t advance the board state
Entry point to solve a sudoku board
Pass in either:
- a bitstring where 0, dot, or space is a blank and any other symbol is a board symbol
- a Sudoku.Board type
Returns: {status, inferences, final_board}
Note: In the event of a non unique solution, the solver will stop at the first solution found. To continue simply extract the state from the final_board.backtrack and pass this back to solve/1 to get more solutions (or :invalid if no more solutions to be found)
Advance the board by one inference step (including guessing).
Computes the next inference and then applies it to the board state to get a new state.
Returns:
- {{:finished, why}, final_board}
- {{:step, step_details}, next_board}
Iteratively compute a next inference to advance the board (including guessing) and then apply that inference to advance the board state.
Stops when we either solve the board, or run out of ways to advance, eg the board is invalid