Jump to content

Sudoku: Difference between revisions

12,863 bytes added ,  2 months ago
m
moved commentary outside the code block.
m (syntax highlighting fixup automation)
m (moved commentary outside the code block.)
 
(18 intermediate revisions by 8 users not shown)
Line 3,168:
 
=={{header|EasyLang}}==
<syntaxhighlight lang="text">len row[] 810
len colrow[] 81090
len boxcol[] 81090
len box[] 90
len grid[] 82
#
funcproc init . .
for pos range= 1 to 81
if pos mod 9 = 01
s$[] = strsplit input " "
. if s$ = ""
dig = number s$[pos mod= 9]input
grid[pos] = dig .
r = pos div 9 len inp[] 0
c for i = pos1 to modlen 9s$
b = r div 3 * 3 + cif divsubstr 3s$ i 1 <> " "
row[r * 10 + dig inp[] &= number substr s$ i 1
col[c * 10 + dig] = 1 .
box[b * 10 + dig] = 1.
.
dig = number inp[(pos - 1) mod 9 + 1]
if dig > 0
grid[pos] = dig
r = (pos - 1) div 9
c = (pos - 1) mod 9
b = r div 3 * 3 + c div 3
row[r * 10 + dig] = 1
col[c * 10 + dig] = 1
box[b * 10 + dig] = 1
.
.
.
call init
#
funcproc display . .
for i range= 1 to 81
write grid[i] & " "
if i mod 3 = 20
write " "
.
if i mod 9 = 80
print ""
.
if i mod 27 = 260
print ""
.
.
.
#
funcproc solve pos . .
while grid[pos] <> 0
pos += 1
.
if pos => 81
# solved
call display
break 1 return
.
r = (pos - 1) div 9
c = (pos - 1) mod 9
b = r div 3 * 3 + c div 3
r *= 10
c *= 10
b *= 10
for d = 1 to 9
if row[r + d] = 0 and col[c + d] = 0 and box[b + d] = 0
grid[pos] = d
row[r + d] = 1
col[c + d] = 1
box[b + d] = 1
call solve pos + 1
row[r + d] = 0
col[c + d] = 0
box[b + d] = 0
.
.
grid[pos] = 0
.
call solve 01
#
input_data
5 3 0 0 2 4 7 0 0
0 0 2 0 0 0 8 0 0
1 0 0 7 0 3 9 0 2
 
0 0 8 0 7 2 0 4 9
0 2 0 9 8 0 0 7 2 0 4 9
70 92 0 0 09 8 0 0 87 0
7 9 0 0 0 0 3 0 58 0 6
 
9 6 0 0 1 0 3 0 0
0 50 0 6 9 0 3 0 1 5 0</syntaxhighlight> 6
9 6 0 0 1 0 3 0 0
0 5 0 6 9 0 0 1 0
 
</syntaxhighlight>
 
=={{header|Elixir}}==
Line 5,142 ⟶ 5,158:
First is a short version:
<syntaxhighlight lang="futurebasic">
include "ConsoleWindow"
include "NSLog.incl"
include "Util_Containers.incl"
 
begin globals
dim as container gC
end globals
 
BeginCDeclaration
short solve_sudoku(short i);
short check_sudoku(short r, short c);
CFMutableStringRef print_sudoku();
EndC
 
BeginCFunction
short sudoku[9][9] = {
{3,0,0,0,0,1,4,0,9},
{7,0,0,0,0,4,2,0,0},
{0,5,0,2,0,0,0,1,0},
{5,7,0,0,4,3,0,6,0},
{0,9,0,0,0,0,0,3,0},
{0,6,0,7,9,0,0,8,5},
{0,8,0,0,0,5,0,4,0},
{0,0,6,4,0,0,0,0,7},
{9,0,5,6,0,0,0,0,3},
};
 
 
short check_sudoku( short r, short c )
{
short i;
short rr, cc;
 
for (i = 0; i < 9; i++)
{
short i;
if (i != c && sudoku[r][i] == sudoku[r][c]) return 0;
short rr, cc;
if (i != r && sudoku[i][c] == sudoku[r][c]) return 0;
rr = r/3 * 3 + i/3;
ccfor (i = c/30; *i 3< +9; i%3;++)
if ((rr != r || cc != c) && sudoku[rr][cc] == sudoku[r][c]) return 0;
}
return -1;
}
 
 
short solve_sudoku( short i )
{
short r, c;
 
if (i < 0) return 0;
else if (i >= 81) return -1;
 
r = i / 9;
c = i % 9;
 
if (sudoku[r][c])
return check_sudoku(r, c) && solve_sudoku(i + 1);
else
for (sudoku[r][c] = 9; sudoku[r][c] > 0; sudoku[r][c]--)
{
if (i solve_sudoku(!= c && sudoku[r][i)] == sudoku[r][c]) return -10;
if (i != r && sudoku[i][c] == sudoku[r][c]) return 0;
rr = r/3 * 3 + i/3;
cc = c/3 * 3 + i%3;
if ((rr != r || cc != c) && sudoku[rr][cc] == sudoku[r][c]) return 0;
}
return 0-1;
}
 
 
CFMutableStringRef print_sudoku()
{
short i, j;
CFMutableStringRef mutStr;
short solve_sudoku( short i )
mutStr = CFStringCreateMutable( kCFAllocatorDefault, 0 );
{
 
short forr, (i = 0c; i < 9; i++)
{
forif (ji =< 0;) jreturn < 90; j++)
else if (i >= 81) return {-1;
CFStringAppendFormat( mutStr, NULL, (CFStringRef)@" %d", sudoku[i][j] );
r = i / }9;
c = i % 9;
CFStringAppendFormat( mutStr, NULL, (CFStringRef)@"\r" );
}
if (sudoku[r][c])
return( mutStr );
return check_sudoku(r, c) && solve_sudoku(i + 1);
}
else
for (sudoku[r][c] = 9; sudoku[r][c] > 0; sudoku[r][c]--)
{
if ( solve_sudoku(i) ) return -1;
}
return 0;
}
CFMutableStringRef print_sudoku()
{
short i, j;
CFMutableStringRef mutStr;
mutStr = CFStringCreateMutable( kCFAllocatorDefault, 0 );
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
CFStringAppendFormat( mutStr, NULL, (CFStringRef)@" %d", sudoku[i][j] );
}
CFStringAppendFormat( mutStr, NULL, (CFStringRef)@"\r" );
}
return( mutStr );
}
EndC
 
Line 5,231 ⟶ 5,244:
toolbox fn print_sudoku() = CFMutableStringRef
 
dim as short solution
dim as CFMutableStringRef cfRef
 
gC = " "
Line 5,243 ⟶ 5,256:
print : print "Sudoku solved:" : print
if ( solution )
gC = " "
cfRef = fn print_sudoku()
fn ContainerCreateWithCFString( cfRef, gC )
print gC
else
print "No solution found"
end if
 
HandleEvents
</syntaxhighlight>
 
Line 5,282 ⟶ 5,297:
More code in this one, but faster execution:
<pre>
include "ConsoleWindow"
include "Tlbx Timer.incl"
 
begin globals
_digits = 9
Line 5,293 ⟶ 5,305:
 
begin record Board
dim as booleanBoolean f(_digits,_digits,_digits)
dim as char match(_digits,_digits)
dim as pointer previousBoard // singly-linked list used to discover repetitions
dim &&
end record
 
dimBoard quiz as board
CFTimeInterval t
dim as long t
dim as double sProgStartTime
 
end globals
 
// 'ordinary' timer used for playing
local fn Milliseconds as long // time in ms since prog start
'~'1
dim as UnsignedWide us
 
long if ( sProgStartTime == 0.0 )
Microseconds( @us )
sProgStartTime = 4294967296.0*us.hi + us.lo
end if
Microseconds( @us )
end fn = (4294967296.0*us.hi + us.lo - sProgStartTime)'*1e-3
 
local fn InitMilliseconds
'~'1
sProgStartTime = 0.0
fn Milliseconds
end fn
 
local mode
local fn CopyBoard( source as ^Board, dest as ^Board )
BlockMoveData( source, dest, sizeof( Board ) )
'~'1
dest.previousBoard = source // linked list
BlockMoveData( source, dest, sizeof( Board ) )
dest.previousBoard = source // linked list
end fn
 
local fn prepare( b as ^Board )
short i, j, n
'~'1
dim as short i, j, n
for i = 1 to _digits
 
for ij = 1 to _digits
for jn = 1 to _digits
b.match[i, j] = 0
for n = 1 to _digits
b.matchf[i, j, n] = 0_true
next n
b.f[i, j, n] = _true
next nj
next ji
next i
end fn
 
local fn printBoard( b as ^Board )
short i, j
'~'1
dim as short i, j
for i = 1 to _digits
 
for ij = 1 to _digits
Print b.match[i, j];
for j = 1 to _digits
next j
Print b.match[i, j];
print
next j
next i
print
next i
end fn
 
local fn verifica( b as ^Board )
short i, j, n, first, x, y, ii
'~'1
Boolean check
dim as short i, j, n, first, x, y, ii
dim as boolean check
check = _true
 
check = _true
for i = 1 to _digits
 
for ij = 1 to _digits
if ( b.match[i, j] == 0 )
for j = 1 to _digits
check = _false
long if ( b.match[i, j] == 0 )
for n = 1 to _digits
check = _false
if ( b.f[i, j, n] != _false )
for n = 1 to _digits
check = _true
long if ( b.f[i, j, n] != _false )
end if
check = _true
next n
end if
if ( check == _false ) then exit fn
next n
end if
if ( check == _false ) then exit fn
next j
end if
next ji
next i
check = _true
 
for j = 1 to _digits
check = _true
for jn = 1 to _digits
for n = 1 to _digits first = 0
for i = 1 to _digits
first = 0
if ( b.match[i, j] == n )
for i = 1 to _digits
long if ( b.match[i, j]first == n0 )
long if ( first == 0 )i
else
first = i
check = _false
xelse
exit fn
check = _false
end if
exit fn
end if
next i
end if
next in
next nj
next j
for i = 1 to _digits
 
for in = 1 to _digits
for n = 1 to _digits first = 0
for j = 1 to _digits
first = 0
if ( b.match[i, j] == n )
for j = 1 to _digits
long if ( b.match[i, j]first == n0 )
long if ( first == 0 )j
else
first = j
check = _false
xelse
exit fn
check = _false
end if
exit fn
end if
next j
end if
next jn
next ni
next i
for x = 0 to ( _nSetH - 1 )
 
for xy = 0 to ( _nSetH_nSetV - 1 )
for y = 0 to ( _nSetVfirst -= 1 )0
for ii = 0 to ( _digits - 1 )
first = 0
i = x * _setH + ii mod _setH + 1
for ii = 0 to ( _digits - 1 )
i j = xy * _setH_setV + ii mod/ _setH + 1
j = y * _setV + ii / _setHif ( b.match[i, j] == +n 1)
long if ( b.match[i, j]first == n0 )
long if ( first == 0 )j
else
first = j
check = _false
xelse
exit fn
check = _false
end if
exit fn
end if
next ii
end if
next iiy
next yx
next x
 
end fn = check
 
 
local fn setCell( b as ^Board, x as short, y as short, n as short) as boolean
dim as short i, j, rx, ry
dim as booleanBoolean check
 
b.match[x, y] = n
for i = 1 to _digits
b.f[x, i, n] = _false
b.f[i, y, n] = _false
next i
 
rx = (x - 1) / _setH
ry = (y - 1) / _setV
 
for i = 1 to _setH
for j = 1 to _setV
b.f[ rx * _setH + i, ry * _setV + j, n ] = _false
next j
next i
 
check = fn verifica( #b )
if ( check == _false ) then exit fn
 
end fn = check
 
 
local fn solve( b as ^Board )
dim as short i, j, n, first, x, y, ii, ppi, ppj
dim as booleanBoolean check
 
check = _true
 
for i = 1 to _digits
for j = 1 to _digits
long if ( b.match[i, j] == 0 )
first = 0
for n = 1 to _digits
long if ( b.f[i, j, n] != _false )
long if ( first == 0 )
first = n
else
xelse
first = -1
exit for
end if
end if
next n
 
long if ( first > 0 )
check = fn setCell( #b, i, j, first )
if ( check == _false ) then exit fn
check = fn solve(#b)
if ( check == _false ) then exit fn
end if
 
end if
next j
next i
 
for i = 1 to _digits
for n = 1 to _digits
first = 0
 
for j = 1 to _digits
if ( b.match[i, j] == n ) then exit for
 
long if ( b.f[i, j, n] != _false ) and ( b.match[i, j] == 0 )
long if ( first == 0 )
first = j
else
xelse
first = -1
exit for
end if
 
end if
 
next j
 
long if ( first > 0 )
check = fn setCell( #b, i, first, n )
if ( check == _false ) then exit fn
check = fn solve(#b)
if ( check == _false ) then exit fn
end if
 
next n
next i
 
 
for j = 1 to _digits
for n = 1 to _digits
first = 0
 
for i = 1 to _digits
if ( b.match[i, j] == n ) then exit for
 
long if ( b.f[i, j, n] != _false ) and ( b.match[i, j] == 0 )
long if ( first == 0 )
first = i
else
xelse
first = -1
exit for
end if
 
end if
 
next i
 
long if ( first > 0 )
check = fn setCell( #b, first, j, n )
if ( check == _false ) then exit fn
check = fn solve(#b)
if ( check == _false ) then exit fn
end if
 
next n
next j
 
 
for x = 0 to ( _nSetH - 1 )
for y = 0 to ( _nSetV - 1 )
 
for n = 1 to _digits
first = 0
 
for ii = 0 to ( _digits - 1 )
 
i = x * _setH + ii mod _setH + 1
j = y * _setV + ii / _setH + 1
 
if ( b.match[i, j] == n ) then exit for
 
long if ( b.f[i, j, n] != _false ) and ( b.match[i, j] == 0 )
long if ( first == 0 )
first = n
ppi = i
ppj = j
else
xelse
first = -1
exit for
end if
end if
 
 
next ii
 
long if ( first > 0 )
check = fn setCell( #b, ppi, ppj, n )
if ( check == _false ) then exit fn
check = fn solve(#b)
if ( check == _false ) then exit fn
end if
 
next n
 
next y
next x
 
end fn = check
 
 
local fn resolve( b as ^Board )
dim as booleanBoolean check, daFinire
dim as long i, j, n
dim as boardBoard localBoard
 
check = fn solve(b)
 
long if ( check == _false )
exit fn
end if
 
daFinire = _false
 
for i = 1 to _digits
for j = 1 to _digits
long if ( b.match[i, j] == 0 )
 
daFinire = _true
 
for n = 1 to _digits
long if ( b.f[i, j, n] != _false )
 
fn CopyBoard( b, @localBoard )
 
check = fn setCell(@localBoard, i, j, n)
 
long if ( check != _false )
check = fn resolve( @localBoard )
long if ( check == -1 )
fn CopyBoard( @localBoard, b )
 
exit fn
end if
end if
 
end if
 
next n
 
end if
next j
next i
 
long if daFinire
else
xelse
check = -1
end if
 
end fn = check
 
 
fn InitMilliseconds
 
fn prepare( @quiz )
Line 5,655 ⟶ 5,642:
DATA 2,8,0,1,3,0,0,0,0
 
dim as short i, j, d
for i = 1 to _digits
for j = 1 to _digits
read d
fn setCell(@quiz, j, i, d)
next j
next i
 
Line 5,666 ⟶ 5,653:
fn printBoard( @quiz )
print : print "-------------------" : print
dim as booleanBoolean check
 
t = fn MillisecondsCACurrentMediaTime
check = fn resolve(@quiz)
t = (fn MillisecondsCACurrentMediaTime - t) * 1000
 
if ( check )
print "solution:"; str$( t/1000.0 ) + " ms"
else
print "No solution found"
end if
fn printBoard( @quiz )
 
HandleEvents
</pre>
 
Line 6,622 ⟶ 6,611:
| 7 8 2 | 6 9 3 | 5 4 1 |
+-------+-------+-------+
</pre>
 
=={{header|jq}}==
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq'''
 
'''Also works with fq, a Go implementation of a large subset of jq'''
 
The two solutions presented here take advantage of jq's built-in backtracking
mechanism.
 
The first solution uses a naive backtracking algorithm which can readily be modified to include more sophisticated
strategies.
 
The second solution modifies `next_row` to use a simple greedy algorithm,
namely, "select the row with the fewest gaps".
 
For the `tarx0134` problem (taken from the
[https://en.wikipedia.org/w/index.php?title=Sudoku_solving_algorithms#Exceptionally_difficult_Sudokus_.28hardest_Sudokus.29 Wikipedia collection] but googleable by that name),
the running time (u+s) is reduced from 264s to 180s on my 3GHz machine.
The memory usage statistics as produced by `/usr/bin/time -lp`
are also shown in the output section below.
<syntaxhighlight lang=jq>
## Utility Functions
def div($b): (. - (. % $b)) / $b;
 
def count(s): reduce s as $_ (0; .+1);
 
def row($i): .[$i];
 
def col($j): transpose | row($j);
 
# pretty print
def pp: .[:3][],"", .[3:6][], "", .[6:][];
 
# Input: 9 x 9 matrix
# Output: linear array corresponding to the specified 3x3 block using IO=0:
# 0,0 0,1 0,2
# 1,0 1,1 1,2
# 2,0 2,1 2,2
def block($i;$j):
def x: range(0;3) + 3*$i;
def y: range(0;3) + 3*$j;
[.[x][y]];
 
# Output: linear block containing .[$i][$j]
def blockOf($i;$j):
block($i|div(3); $j|div(3));
 
# Input: the entire Sudoku matrix
# Output: the update matrix after solving for row $i
def solveRow($i):
def s:
(.[$i] | index(0)) as $j
| if $j
then ((( [range(1;10)] - row($i)) - col($j)) - blockOf($i;$j) ) as $candidates
| if $candidates|length == 0 then empty
else $candidates[] as $x
| .[$i][$j] = $x
| s
end
else .
end;
s;
 
def distinct: map(select(. != 0)) | length - (unique|length) == 0;
 
# Is the Sudoku valid?
def valid:
. as $in
| length as $l
| all(.[]; distinct) and
all( range(0;9); . as $i | $in | col($i) | distinct ) and
all( range(0;3); . as $i | all(range(0;3); . as $j
| $in | block($i;$j) | distinct ));
 
# input: the full puzzle in its current state
# output: null if there is no candidate next row
def next_row:
first( range(0; length) as $i | select(row($i)|index(0)) | $i) // null;
 
def solve(problem):
def s:
next_row as $ix
| if $ix then solveRow($ix) | s
else .
end;
if problem|valid then first(problem|s) | pp
else "The Sukoku puzzle is invalid."
end;
 
# Rating Program: dukuso's suexratt
# Rating: 3311
# Poster: tarek
# Label: tarx0134
# ........8..3...4...9..2..6.....79.......612...6.5.2.7...8...5...1.....2.4.5.....3
def tarx0134:
[[0,0,0,0,0,0,0,0,8],
[0,0,3,0,0,0,4,0,0],
[0,9,0,0,2,0,0,6,0],
[0,0,0,0,7,9,0,0,0],
[0,0,0,0,6,1,2,0,0],
[0,6,0,5,0,2,0,7,0],
[0,0,8,0,0,0,5,0,0],
[0,1,0,0,0,0,0,2,0],
[4,0,5,0,0,0,0,0,3]];
 
# An invalid puzzle, for checking `valid`:
def unsolvable:
[[3,9,4,3,0,2,6,7,0],
[0,0,0,3,0,0,4,0,0],
[5,0,0,6,9,0,0,2,0],
[0,4,5,0,0,0,9,0,0],
[6,0,0,0,0,0,0,0,7],
[0,0,7,0,0,0,5,8,0],
[0,1,0,0,6,7,0,0,8],
[0,0,9,0,0,8,0,0,0],
[0,2,6,4,0,0,7,3,5]] ;
 
solve(tarx0134)
</syntaxhighlight>
 
====Greedy Algorithm====
Replace `def next_row:` with the following definition:
<syntaxhighlight lang=jq>
# select a row with the fewest number of unknowns
def next_row:
length as $len
| . as $in
| reduce range(0;length) as $i ([];
. + [ [ count( $in[$i][] | select(. != 0)), $i] ] )
| map(select(.[0] != $len))
| if length == 0 then null
else max_by(.[0]) | .[1]
end ;
</syntaxhighlight>
 
{{output}}
For the naive next_row:
<pre>
[6,2,1,9,4,3,7,5,8]
[7,8,3,6,1,5,4,9,2]
[5,9,4,7,2,8,3,6,1]
 
[1,4,2,8,7,9,6,3,5]
[3,5,7,4,6,1,2,8,9]
[8,6,9,5,3,2,1,7,4]
 
[2,3,8,1,9,7,5,4,6]
[9,1,6,3,5,4,8,2,7]
[4,7,5,2,8,6,9,1,3]
 
# Summary performance statistics:
user 260.89
sys 3.32
2240512 maximum resident set size
1302528 peak memory footprint
</pre>
 
For the greedy next_row algorithm, jq produces the same solution
with the following performance statistics:
<pre>
user 177.94
sys 2.12
2224128 maximum resident set size
1277952 peak memory footprint
</pre>
gojq stats for the greedy algorithm:
<pre>
user 62.19
sys 7.44
7458418688 maximum resident set size
7683284992 peak memory footprint
</pre>
 
fq stats for the greedy algorithm:
<pre>
user 73.56
sys 5.34
6084091904 maximum resident set size
6436892672 peak memory footprint
</pre>
 
Line 6,648 ⟶ 6,818:
for i in 1:81
if grid[i] == 0
t = Dict{Int64, VoidNothing}()
 
for j in 1:81
Line 9,911 ⟶ 10,081:
=={{header|Python}}==
See [http://www2.warwick.ac.uk/fac/sci/moac/currentstudents/peter_cock/python/sudoku/ Solving Sudoku puzzles with Python] for GPL'd solvers of increasing complexity of algorithm.
 
===Backtrack===
 
A simple backtrack algorithm -- Quick but may take longer if the grid had been more than 9 x 9
Line 9,998 ⟶ 10,170:
raw_input()
</syntaxhighlight>
 
===Search + Wave Function Collapse===
 
A Sudoku solver using search guided by the principles of wave function collapse.
<syntaxhighlight lang="python">
 
 
sudoku = [
# cell value # cell number
0, 0, 4, 0, 5, 0, 0, 0, 0, # 0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 0, 0, 7, 3, 4, 6, 0, 0, # 9, 10, 11, 12, 13, 14, 15, 16, 17,
0, 0, 3, 0, 2, 1, 0, 4, 9, # 18, 19, 20, 21, 22, 23, 24, 25, 26,
0, 3, 5, 0, 9, 0, 4, 8, 0, # 27, 28, 29, 30, 31, 32, 33, 34, 35,
0, 9, 0, 0, 0, 0, 0, 3, 0, # 36, 37, 38, 39, 40, 41, 42, 43, 44,
0, 7, 6, 0, 1, 0, 9, 2, 0, # 45, 46, 47, 48, 49, 50, 51, 52, 53,
3, 1, 0, 9, 7, 0, 2, 0, 0, # 54, 55, 56, 57, 58, 59, 60, 61, 62,
0, 0, 9, 1, 8, 2, 0, 0, 3, # 63, 64, 65, 66, 67, 68, 69, 70, 71,
0, 0, 0, 0, 6, 0, 1, 0, 0, # 72, 73, 74, 75, 76, 77, 78, 79, 80
# zero = empty.
]
 
numbers = {1,2,3,4,5,6,7,8,9}
 
def options(cell,sudoku):
""" determines the degree of freedom for a cell. """
column = {v for ix, v in enumerate(sudoku) if ix % 9 == cell % 9}
row = {v for ix, v in enumerate(sudoku) if ix // 9 == cell // 9}
box = {v for ix, v in enumerate(sudoku) if (ix // (9 * 3) == cell // (9 * 3)) and ((ix % 9) // 3 == (cell % 9) // 3)}
return numbers - (box | row | column)
 
initial_state = sudoku[:] # the sudoku is our initial state.
 
job_queue = [initial_state] # we need the jobqueue in case of ambiguity of choice.
 
while job_queue:
state = job_queue.pop(0)
if not any(i==0 for i in state): # no missing values means that the sudoku is solved.
break
 
# determine the degrees of freedom for each cell.
degrees_of_freedom = [0 if v!=0 else len(options(ix,state)) for ix,v in enumerate(state)]
# find cell with least freedom.
least_freedom = min(v for v in degrees_of_freedom if v > 0)
cell = degrees_of_freedom.index(least_freedom)
 
for option in options(cell, state): # for each option we add the new state to the queue.
new_state = state[:]
new_state[cell] = option
job_queue.append(new_state)
 
# finally - print out the solution
for i in range(9):
print(state[i*9:i*9+9])
 
# [2, 6, 4, 8, 5, 9, 3, 1, 7]
# [9, 8, 1, 7, 3, 4, 6, 5, 2]
# [7, 5, 3, 6, 2, 1, 8, 4, 9]
# [1, 3, 5, 2, 9, 7, 4, 8, 6]
# [8, 9, 2, 5, 4, 6, 7, 3, 1]
# [4, 7, 6, 3, 1, 8, 9, 2, 5]
# [3, 1, 8, 9, 7, 5, 2, 6, 4]
# [6, 4, 9, 1, 8, 2, 5, 7, 3]
# [5, 2, 7, 4, 6, 3, 1, 9, 8]
 
</syntaxhighlight>
 
This solver found the 45 unknown values in 45 steps.
 
=={{header|Racket}}==
Line 12,875 ⟶ 13,114:
 
=={{header|Tailspin}}==
There is a blog post about how this code was developed: https://tobega.blogspot.com/2020/05/creating-algorithm.html
<syntaxhighlight lang="tailspin">
templates deduceRemainingDigits
templates findOpenPosition
@:{options: 10"1"};
$ -> \[i;j](when <[]?($::length <..~$@findOpenPosition.options::raw>)> do @findOpenPosition: {row: $i, col: $j, options: ($::length)"1"}; \) -> !VOID
$@ !
end findOpenPosition
Line 12,896 ⟶ 13,136:
@: $;
$ -> findOpenPosition -> #
when <{options: <=0"1">}> do row´1:[] !
when <{options: <=10"1">}> do $@ !
when <> do def next: $;
$@ -> selectFirst&{pos: $next} -> deduceRemainingDigits
-> \(when <~=row´1:[]> do @deduceRemainingDigits: $; {options: 10"1"} !
when <=row´1:[]> do ^@deduceRemainingDigits($next.row;$next.col;1)
-> { $next..., options: $next.options-1"1"} ! \) -> #
end deduceRemainingDigits
Line 12,926 ⟶ 13,166:
assert row´1:[
col´1:[[],3,4,6,7,8,9,1,2],
$sample(row´2..last)...] -> deduceRemainingDigits <=row´1:[]> 'no remaining options returns empty'
 
assert row´1:[
Line 12,987 ⟶ 13,227:
templates solveSudoku
$ -> parseSudoku -> deduceRemainingDigits -> #
when <=row´1:[]> do 'No result found' !
when <> do $ -> \[i](
'$(col´1..col´3)...;|$(col´4..col´6)...;|$(col´7..col´9)...;$#10;' !
Line 13,661 ⟶ 13,901:
2 4 3 1 5 7 8 6 9
5 1 9 8 3 6 7 2 4</pre>
 
===Alternate version===
A faster version adapted from the C solution
<syntaxhighlight lang="vb">
'VBScript Sudoku solver. Fast recursive algorithm adapted from the C version
'It can read a problem passed in the command line or from a file /f:textfile
'if no problem passed it solves a hardwired problem (See the prob0 string)
'problem string can have 0's or dots in the place of unknown values. All chars different from .0123456789 are ignored
 
Option explicit
Sub print(s):
On Error Resume Next
WScript.stdout.Write (s)
If err= &h80070006& Then WScript.Echo " Please run this script with CScript": WScript.quit
End Sub
 
function parseprob(s)'problem string to array
Dim i,j,m
print "parsing: " & s & vbCrLf & vbcrlf
j=0
For i=1 To Len(s)
m=Mid(s,i,1)
Select Case m
Case "0","1","2","3","4","5","6","7","8","9"
sdku(j)=cint(m)
j=j+1
Case "."
sdku(j)=0
j=j+1
Case Else 'all other chars are ignored as separators
End Select
Next
' print j
If j<>81 Then parseprob=false Else parseprob=True
End function
 
sub getprob 'get problem from file or from command line or from
Dim s,s1
With WScript.Arguments.Named
If .exists("f") Then
s1=.item("f")
If InStr(s1,"\")=0 Then s1= Left(WScript.ScriptFullName, InStrRev(WScript.ScriptFullName, "\"))&s1
On Error Resume Next
s= CreateObject("Scripting.FileSystemObject").OpenTextFile (s1, 1).readall
If err Then print "can't open file " & s1 : parseprob(prob0): Exit sub
If parseprob(s) =True Then Exit sub
End if
End With
With WScript.Arguments.Unnamed
If .count<>0 Then
s1=.Item(0)
If parseprob(s1)=True Then exit sub
End if
End With
parseprob(prob0)
End sub
 
function solve(x,ByVal pos)
'print pos & vbcrlf
'display(x)
Dim row,col,i,j,used
solve=False
If pos=81 Then solve= true :Exit function
row= pos\9
col=pos mod 9
If x(pos) Then solve=solve(x,pos+1):Exit Function
used=0
For i=0 To 8
used=used Or pwr(x(i * 9 + col))
Next
For i=0 To 8
used=used Or pwr(x(row*9 + i))
next
row = (row\ 3) * 3
col = (col \3) * 3
For i=row To row+2
For j=col To col+2
' print i & " " & j &vbcrlf
used = used Or pwr(x(i*9+j))
Next
Next
'print pos & " " & Hex(used) & vbcrlf
For i=1 To 9
If (used And pwr(i))=0 Then
x(pos)=i
'print pos & " " & i & " " & num2bin((used)) & vbcrlf
solve= solve(x,pos+1)
If solve=True Then Exit Function
'x(pos)=0
End If
Next
x(pos)=0
solve=False
End Function
 
Sub display(x)
Dim i,s
For i=0 To 80
If i mod 9=0 Then print s & vbCrLf :s=""
If i mod 27=0 Then print vbCrLf
If i mod 3=0 Then s=s & " "
s=s& x(i)& " "
Next
print s & vbCrLf
End Sub
 
Dim pwr:pwr=Array(1,2,4,8,16,32,64,128,256,512,1024,2048)
Dim prob0:prob0= "001005070"&"920600000"& "008000600"&"090020401"& "000000000" & "304080090" & "007000300" & "000007069" & "010800700"
Dim sdku(81),Time
getprob
print "The problem"
display(sdku)
Time=Timer
If solve (sdku,0) Then
print vbcrlf &"solution found" & vbcrlf
display(sdku)
Else
print "no solution found " & vbcrlf
End if
print vbcrlf & "time: " & Timer-Time & " seconds" & vbcrlf
</syntaxhighlight>
{{out}}
<small>
<pre>
parsing: 001005070920600000008000600090020401000000000304080090007000300000007069010800700
 
The problem
 
0 0 1 0 0 5 0 7 0
9 2 0 6 0 0 0 0 0
0 0 8 0 0 0 6 0 0
 
0 9 0 0 2 0 4 0 1
0 0 0 0 0 0 0 0 0
3 0 4 0 8 0 0 9 0
 
0 0 7 0 0 0 3 0 0
0 0 0 0 0 7 0 6 9
0 1 0 8 0 0 7 0 0
 
solution found
 
6 3 1 2 4 5 9 7 8
9 2 5 6 7 8 1 4 3
4 7 8 3 1 9 6 5 2
 
7 9 6 5 2 3 4 8 1
1 8 2 9 6 4 5 3 7
3 5 4 7 8 1 2 9 6
 
8 6 7 4 9 2 3 1 5
2 4 3 1 5 7 8 6 9
5 1 9 8 3 6 7 2 4
 
time: 0.3710938 seconds
</pre>
</small>
 
=={{header|Wren}}==
{{trans|Kotlin}}
<syntaxhighlight lang="ecmascriptwren">class Sudoku {
construct new(rows) {
if (rows.count != 9 || rows.any { |r| r.count != 9 }) {
6

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.