Posted 29 March 2013 - 08:27 AM
Hi,
I was playing sudoku the other day and wanted a way to check my results to see if they worked, so I made a sudoku checker. Then I got a bit stuck on one and though why don't I make it solve one for me
Code:
It is terrible , i'm not going to lie. It will only solve the basic sudoku's, but it is a start and I haven't seen anyone else even attempt it so I though I may as well post it and maybe give some people some inspiration.
The way it works is it checks for every possibility for each place and if there is one possibility then it must be that number so it puts it there and runs itself with the new numbers. The reason it won't solve advanced puzzles is because it won't recognise that with a 2&3 for possibilities next to eachother the 2 and the 3 have to go on that row so it cannot be a 2 or 3 in the same row etc. If someone has a way to solve this please implement it because I have tried and failed 7 times with about 300 lines of code each time.
If anyone is interested in improving this feel free to use the code or if you would like some help or want to help just post a comment below.
Thanks for reading
I was playing sudoku the other day and wanted a way to check my results to see if they worked, so I made a sudoku checker. Then I got a bit stuck on one and though why don't I make it solve one for me
Code:
Spoiler
local args = { ... }
split = function( str )
local t = { }
for i = 1,str:len( ) do
t[i] = str:sub( i, i )
end
return t
end
puzzle = {
{5,0,4,3,8,0,0,0,0};
{0,9,0,5,0,0,2,0,0};
{1,0,0,0,6,4,8,0,0};
{0,0,5,1,9,0,0,0,7};
{0,0,6,0,0,0,9,0,0};
{3,0,0,0,7,6,4,0,0};
{0,0,2,7,4,0,0,0,1};
{0,0,1,0,0,9,0,2,0};
{0,0,0,0,2,1,3,0,9};
}
if args[2] then
k = fs.open( args[2], "r" )
local con = { }
for i = 1,9 do
con[i] = k.readLine( )
end
k.close( )
for i = 1,9 do
print( con[i] )
con[i] = split( con[i], "" )
print( "here" )
for k = 1,9 do
con[i][k] = tonumber( con[i][k] ) or 0
end
end
puzzle = con
end
term.clear( )
local correctpuzzle = {
{8,3,2,6,7,5,1,4,9};
{0,4,9,1,3,2,8,5,6};
{5,6,1,4,9,8,3,2,7};
{4,1,5,9,8,7,2,6,3};
{9,2,6,3,5,1,4,7,8};
{3,8,7,2,6,4,5,9,1};
{2,5,3,7,1,6,9,8,4};
{6,9,4,8,2,3,7,1,5};
{1,7,8,5,4,9,6,3,2};
}
local function checkBox( n )
if n < 1 or n > 9 then
return nil
end
local x = 0
local y = 1
while n >= 4 do
y = y+1
n = n-3
end
x = x+n
local n = { }
for i = x*3-2, x*3 do
for k = y*3-2, y*3 do
n[puzzle[k][i]] = true
end
end
for i = 1,9 do
if not n[i] or n[i] ~= true then
return false
end
end
return true
end
local function checkColumn( n )
local num = { }
for i = 1,9 do
num[puzzle[i][n]] = true
end
for i = 1,9 do
if not num[i] or num[i] ~= true then
return false
end
end
return true
end
local function checkRow( n )
local num = { }
for i = 1,9 do
num[puzzle[n][i]] = true
end
for i = 1,9 do
if not num[i] or num[i] ~= true then
return false
end
end
return true
end
local function getPuzzle( )
local x = 1
local y = 1
while true do
for i = 1,9 do
for k = 1,9 do
if i == y and x == k then
term.setBackgroundColour( colours.blue )
else
term.setBackgroundColour( colours.lightBlue )
end
term.setCursorPos( k, i )
term.write( tostring( puzzle[i][k] ):sub( 1, 1 ) )
end
end
term.setCursorPos( 1, 10 )
ev = { os.pullEvent( ) }
if ev[1] == "key" then
if ev[2] == keys.up and y > 1 then
y = y - 1
elseif ev[2] == keys.down and y < 9 then
y = y + 1
elseif ev[2] == keys.left and x > 1 then
x = x - 1
elseif ev[2] == keys.right and x < 9 then
x = x + 1
elseif ev[2] == keys.backspace then
return false
elseif ev[2] == keys.enter then
return true
end
elseif ev[1] == "char" then
puzzle[y][x] = tonumber( ev[2] ) or 0
end
end
end
local function checkPuzzle( )
local message = "Failed"
for i = 1,9 do
local f = checkRow( i )
local s = checkColumn( i )
local t = checkBox( i )
if not f or not s or not t then
if not f then
message = message.."; R"..i
end
if not s then
message = message.."; C"..i
end
if not t then
message = message.."; B"..i
end
failed = true
end
end
return message == "Failed" and "Fine" or message
end
local function getNumbers( ty, n, t )
local num = { }
if ty == "row" then
for i = 1,9 do
table.insert( num, t[n][i].n )
end
elseif ty == "column" then
for i = 1,9 do
table.insert( num, t[i][n].n )
end
elseif ty == "box" then
local x = 0
local y = 1
while n >= 4 do
y = y+1
n = n-3
end
x = x+n
local n = { }
for i = x*3-2, x*3 do
for k = y*3-2, y*3 do
table.insert( num, t[k][i].n )
end
end
end
return num
end
local function solve( t, try )
local backupofpuzzle = { unpack( t ) }
if try > 1600 then
return "unable to solve"
end
if math.floor( try/400 ) == try/400 then
print( "This is taking a while" )
sleep( 0.1 )
end
--converts it into a new format
for i = 1,9 do
for k = 1,9 do
t[i][k] = { n = t[i][k], pos = { } }
for z = 1,9 do
t[i][k].pos[z] = true
end
end
end
--removes incorrect possibilities
for i = 1,9 do
--box checking
local ns = getNumbers( "box", i, t )
local n = i
local x = 0
local y = 1
while n >= 4 do
y = y+1
n = n-3
end
x = x+n
for m = 1,#ns do
for y = y*3-2, y*3 do
for x = x*3-2, x*3 do
if t[y][x].n == 0 then
t[y][x].pos[ns[m]] = false
end
end
end
end
--row checking
local ns = getNumbers( "row", i, t )
for m = 1,#ns do
for x = 1,9 do
if t[i][x].n == 0 then
t[i][x].pos[ns[m]] = false
end
end
end
--column checking
local ns = getNumbers( "column", i, t )
for m = 1,#ns do
for x = 1,9 do
if t[x][i].n == 0 then
t[x][i].pos[ns[m]] = false
end
end
end
end
--updates the numbers ( if there is only one possibility then it has to be that... )
for i = 1,9 do
for k = 1,9 do
local correct = 0
for z = 1,9 do
if t[i][k].pos[z] == true then
correct = correct+1
end
end
if correct == 1 then
for z = 1,9 do
if t[i][k].pos[z] and t[i][k].n == 0 then
t[i][k].n = z
end
end
end
end
end
--checks to see if it has completed the puzzle
local solved = true
for i = 1,9 do
for k = 1,9 do
if t[k][i].n == 0 then
solved = false
end
end
end
--if it isn't solved then try again and
if not solved then
--converts it back into just numbers
for i = 1,9 do
for k = 1,9 do
t[i][k] = t[i][k].n
end
end
if t == backupofpuzzle then
for i = 1,9 do
for k = 1,9 do
t[i][k] = { n = t[i][k] }
end
end
else
return solve( t, try+1 )
end
end
--makes the rows of numbers into a string
local line = { }
for i = 1,9 do
line[i] = ""
for k = 1,9 do
line[i] = line[i]..tostring( t[i][k].n )
end
line[i] = line[i].."\n"
end
return unpack( line )
end
if not getPuzzle( ) then
term.setBackgroundColour( colours.black )
term.setTextColour( colours.yellow )
print( "You Quitted" )
return
end
local failed = false
local message = "Failed"
if args[1] == "check" then
if checkPuzzle( puzzle ) ~= "Fine" then
term.setBackgroundColour( colours.black )
term.setTextColour( colours.red )
print( checkPuzzle( puzzle ) )
return
end
term.setBackgroundColour( colours.black )
term.setTextColour( colours.lime )
print( "It Works!" )
elseif args[1] == "solve" then
term.setBackgroundColour( colours.green )
print( solve( puzzle, 1 ) )
end
It is terrible , i'm not going to lie. It will only solve the basic sudoku's, but it is a start and I haven't seen anyone else even attempt it so I though I may as well post it and maybe give some people some inspiration.
The way it works is it checks for every possibility for each place and if there is one possibility then it must be that number so it puts it there and runs itself with the new numbers. The reason it won't solve advanced puzzles is because it won't recognise that with a 2&3 for possibilities next to eachother the 2 and the 3 have to go on that row so it cannot be a 2 or 3 in the same row etc. If someone has a way to solve this please implement it because I have tried and failed 7 times with about 300 lines of code each time.
If anyone is interested in improving this feel free to use the code or if you would like some help or want to help just post a comment below.
Thanks for reading