I am writing a sudoku solver in scheme. I represent the board cells as a 3x3 vector of 3x3 vectors with a list of the candidates numbers in each cell. So for example a blank board and updating one of its cells is
(define blank-board-cell (for/list ([x 9]) (add1 x)))
(define blank-row (make-vector 9 blank-board-cell))
(define blank-board (make-vector 9 blank-row))
(define (board-ref b row col)
(vector-ref (vector-ref b row) col))
(define (board-update b target-row target-col new-cell)
(for/vector ([row (vector-length b)])
(for/vector ([col (vector-length b)])
(cond [(and (= row target-row)
(= col target-col))
new-cell]
[else (board-ref b row col)]))))
I would like to implement the naked single and hidden single strategies for solving the board. Naked single: find empty cells whose value can be deduced from looking at the contents of its row, column and 3x3 block. If 8 numbers have already been assigned to these neighboring cells then the empty cell must house the last remaining number and that number must be removed from the cells in the same row, column and 3x3 block.
In Java/imperative style for example this would look like
boolean nakedSingles()
{
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
HashSet<Integer> cellCandidates = board[row][col].candidates;
if (cellCandidates.size()==1)
{
board[row][col].setValue(cellCandidates.iterator().next());
//remove candidate from neighboring cells
return true;
}
}
}
return false;
}
The "translation" to scheme "pseudocode" I am heading to
(define (naked-single b)
(for*/vector ([row (in-range (vector-length b))]
[col (in-range (vector-length b))])
(if (= 1 (length (board-ref b row col)))
; set candidate and remove it from cells in row/col
; and return #t
#f)))
Does this look sensible/correct?
Hidden Single: By looking at the row, column and 3x3 block it is clear that there is only one candidate possible although the cell itself might have several candidates. We assign that candidate to the cell and remove it from the cells in the same row, column and 3x3 block.
In Java/imperative style for example this would look like
boolean hiddenSingles()
{
int [] unitCandidates = new int[10];
// For each row, column or boxID
for (int unitSelect = 0; unitSelect < 3; unitSelect++)
{
for (int i = 0; i < 9; i++)
{
if (unitSelect == 0)
{
unit = getRow(i);
}
else if (unitSelect == 1)
{
unit = getCol(i);
}
else if (unitSelect == 2)
{
unit = getBox(i + 1);
}
for (int n = 1; n <= 9; n++)
{
unitCandidates[n] = 0;
}
for (Integer[] elem:unit)
{
int row = elem[0];
int col = elem[1];
if (board[row][col].getValue() == 0)
{
for (int cand:board[row][col].candidates)
{
unitCandidates[cand] += 1;
}
}
}
int foundDigit = 0;
for (int n = 1; n <= 9; n++)
{
// Check for hidden single
if (unitCandidates[n] == 1)
{
// Found hidden single
foundDigit = n;
break;
}
}
// If a hidden single was found, check what cell
// contained that hidden single and set cellvalue
if (foundDigit != 0)
{
for (Integer[] elem:unit)
{
int row = elem[0];
int col = elem[1];
if (board[row][col].getValue() == 0)
{
if (board[row]col].candidates.contains((Object)
foundDigit))
{
board[row][col].setValue(foundDigit);
removeDigitfrom(row,col);
return true;
}
}
}
}
}
}
return false;
}
This one is slightly more complicated to translate into scheme not sure what the more elegant way is? (I can brute force it with nested for loops).