Created
June 8, 2012 17:14
-
-
Save dave1707/2896942 to your computer and use it in GitHub Desktop.
sudoku
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- sudoku solver | |
-- written for the iPad using Codea | |
--# board | |
board = class() | |
function board:squares() | |
-- draw 9x9 board with red or green squares | |
local x, y, z | |
rectMode(CENTER) | |
strokeWidth(0) | |
z = 0 | |
for y=9,1,-1 do | |
for x=1,9 do | |
z = z + 1 | |
fill(255,0,0,255) | |
if btabs[z] == 1 then | |
fill(0,128,0,256) | |
end | |
rect(50+x*60,250+y*60,58,58) | |
end | |
end | |
rectMode(STANDARD) | |
end | |
function board:values() | |
-- draw the selection row with red or green squares | |
local x | |
rectMode(CENTER) | |
for x=1,9 do | |
fill(255,0,0,255) | |
if selected == x then | |
fill(0,128,0,256) | |
end | |
rect(50+x*60,200,58,58) | |
end | |
for x=1,9 do | |
fill(255,255,255) | |
text(x,50+x*60,200) | |
end | |
rectMode(STANDARD) | |
end | |
function board:border() | |
-- draw border arount 9x9 board | |
strokeWidth(10) | |
noFill() | |
rect(70,270,560,560) | |
strokeWidth(1) | |
fill(255,255,255,255) | |
end | |
function board:lines() | |
-- draw the lines to define the 3x3 squares | |
strokeWidth(2) | |
line(260,280,260,820) | |
line(440,280,440,820) | |
line(80,640,630,640) | |
line(80,460,630,460) | |
end | |
function board:numbers() | |
-- display the numbers in the 9x9 board squares | |
local x, y | |
local v = 0 | |
for y=9,1,-1 do | |
for x=1,9 do | |
v = v + 1 | |
if btabv[v] == 0 then | |
text("",50+x*60,250+y*60) | |
else | |
text(btabv[v],50+x*60,250+y*60) | |
end | |
end | |
end | |
end | |
function board:touch(touch) | |
-- check if the select, board, or buttons were touched | |
if count == 0 then | |
board:selectindex(touch.x,touch.y) | |
board:boardindex(touch.x,touch.y) | |
end | |
button:pressed(touch.x,touch.y) | |
end | |
function board:selectindex(x,y) | |
-- get the value that was selected in the select row | |
local z | |
for z = 1,9 do | |
if x > stabl[z] and x < stabr[z] then | |
if y > stabb[z] and y < stabt[z] then | |
selected = z | |
return | |
end | |
end | |
end | |
end | |
function board:boardindex(x,y) | |
-- put the number selected into the 9x9 board square selected | |
local z | |
for z = 1,81 do | |
if x > btabl[z] and x < btabr[z] then | |
if y > btabb[z] and y < btabt[z] then | |
if btabv[z] ~= 0 then | |
btabv[z] = 0 | |
btabs[z] = 0 | |
return | |
end | |
if check:duplicates(selected,z) == 0 then | |
btabv[z] = selected | |
btabs[z] = 1 | |
return | |
end | |
end | |
end | |
end | |
end | |
--# button | |
button = class() | |
function button:show() | |
-- show title and buttons with one call | |
button:title() | |
button:start(btstart) | |
button:exit(btexit) | |
button:pause(btpause) | |
end | |
function button:set(s,e,p) | |
-- set the different colors for the buttons | |
btstart = s | |
btexit = e | |
btpause = p | |
end | |
function button:title() | |
-- show title | |
fill(50,50,50,255) | |
rectMode(CENTER) | |
rect(350,975,200,50) | |
fill(255) | |
text("Sudoku Solver",350,975) | |
rectMode(STANDARD) | |
end | |
function button:solution() | |
-- show solution value | |
str = string.format("Solution %d",solution) | |
rectMode(CENTER) | |
fill(255,0,0,255) | |
rect(200,100,150,50) | |
fill(255) | |
text(str,200,100) | |
rectMode(STANDARD) | |
end | |
function button:count() | |
-- show count value | |
local str | |
str = string.format("Count %d",count) | |
rectMode(CENTER) | |
fill(255,0,0,255) | |
rect(500,100,150,50) | |
fill(255) | |
text(str,500,100) | |
rectMode(STANDARD) | |
end | |
function button:start(x) | |
-- show start, next, or done button | |
local str | |
if x == 0 then | |
fill(0,0,128,255) | |
else | |
fill(0,128,0,255) | |
end | |
rectMode(CENTER) | |
rect(150,900,100,50) | |
fill(255) | |
if count > 0 then | |
str = "NEXT" | |
else | |
str = "START" | |
end | |
if offset < 1 then | |
str = "DONE" | |
end | |
text(str,150,900) | |
rectMode(STANDARD) | |
end | |
function button:exit() | |
-- show exit button | |
fill(0,0,128,255) | |
rectMode(CENTER) | |
rect(350,900,100,50) | |
fill(255) | |
text("EXIT",350,900) | |
rectMode(STANDARD) | |
end | |
function button:pause(x) | |
-- show pause button | |
if x == 0 then | |
fill(0,0,128,255) | |
else | |
fill(0,128,0,255) | |
end | |
rectMode(CENTER) | |
rect(550,900,100,50) | |
fill(255) | |
text("PAUSE",550,900) | |
rectMode(STANDARD) | |
end | |
function button:pressed(x,y) | |
-- check if start button was selected | |
if x > bstart[1] and x < bstart[2] then | |
if y > bstart[3] and y < bstart[4] then | |
if offset < 1 then | |
return | |
end | |
selected = 0 | |
board:values() | |
button:set(1,0,0) | |
button:show() | |
return | |
end | |
end | |
-- check if exit button was selected | |
if x > bexit[1] and x < bexit[2] then | |
if y > bexit[3] and y < bexit[4] then | |
close() | |
end | |
end | |
-- check if pause button was selected | |
if x > bpause[1] and x < bpause[2] then | |
if y > bpause[3] and y < bpause[4] then | |
button:set(0,0,1) | |
button:show() | |
return | |
end | |
end | |
end | |
--# check | |
check = class() | |
function check:horizontal(s,i) | |
-- check if there are duplicate horizontal numbers | |
local val, z | |
val = math.ceil(i/9)-1 | |
val = val * 9 + 1 | |
for z=val,val+8 do | |
if btabv[z] == s then | |
return(1) -- dups | |
end | |
end | |
return(0) -- no dups | |
end | |
function check:vertical(s,i) | |
-- check if there are duplicate vertical numbers | |
local val, z | |
val = math.fmod(i,9) | |
for z=val,val+72,9 do | |
if btabv[z] == s then | |
return(1) -- dups | |
end | |
end | |
return(0) -- no dups | |
end | |
function check:square(s,i) | |
-- check if there are duplicate numbers in the 3x3 square | |
local w1, w2, w3, x, z | |
w1 = i - 1 | |
w2 = math.floor(w1 / 9) * 9 | |
w3 = math.fmod(w1,3) + w2 - math.floor(w2 / 27) * 27 | |
x = i - w3 | |
for z = 1,9 do | |
if btabv[x] == s then | |
return(1) -- dup | |
end | |
x = x + 1 | |
if z == 3 or z == 6 then | |
x = x + 6 | |
end | |
end | |
return(0) -- no dups | |
end | |
function check:duplicates(s,i) | |
-- check for duplicates | |
if check:horizontal(s,i) == 1 then | |
return(1) -- dup | |
end | |
if check:vertical(s,i) == 1 then | |
return(1) -- dup | |
end | |
if check:square(s,i) == 1 then | |
return(1) -- dup | |
end | |
return(0) -- no dups | |
end | |
--# Main | |
function setup() | |
displayMode(FULLSCREEN) | |
background(40, 40, 50) | |
backingMode(RETAINED) | |
-- define variables | |
add = 1 | |
btstart = 0 | |
btexit = 0 | |
btpause = 1 | |
selected = 0 | |
solution = 0 | |
count = 0 | |
offset = 1 | |
-- tables used for the 9x9 board | |
btabv={} | |
btabs={} | |
btabl={} | |
btabr={} | |
btabt={} | |
btabb={} | |
-- tables used for the selectio numbers | |
stabl={} | |
stabr={} | |
stabt={} | |
stabb={} | |
-- tables used for the buttons | |
bstart={} | |
bexit={} | |
bpause={} | |
-- initialize the tables | |
tables:board() | |
tables:select() | |
tables:set() | |
tables:buttons() | |
end | |
-- This function gets called once every frame | |
function draw() | |
-- draw everything once per cycle | |
board:squares() | |
board:border() | |
board:values() | |
board:lines() | |
board:numbers() | |
button:show() | |
search:answer() | |
button:count() | |
button:solution() | |
end | |
function touched(touch) | |
-- something was touched | |
if touch.state == ENDED then | |
board:touch(touch) | |
end | |
end | |
--# search | |
search = class() | |
function search:answer() | |
-- search for a solution | |
if btstart == 0 then | |
return | |
end | |
local loop = 0 | |
-- do a maximun of 100 checks per draw cycle | |
while loop < 100 do | |
count = count + 1 | |
if btabs[offset] == 1 then | |
if add == 1 then | |
search:plus() | |
else | |
search:minus() | |
end | |
end | |
-- no more solutions found | |
if offset < 1 then | |
button:set(0,0,1) | |
button:count() | |
return | |
end | |
-- a solution was found | |
if offset > 81 then | |
offset = 81 | |
add = 0 | |
-- comment out next line to not stop at a solution | |
button:set(0,0,1) | |
button:show() | |
solution = solution + 1 | |
button:count() | |
return | |
end | |
-- increment square values and inc or dec offset | |
if btabv[offset] < 9 then | |
btabv[offset] = btabv[offset] + 1 | |
local h | |
h = btabv[offset] | |
btabv[offset] = 0 | |
if check:duplicates(h,offset) == 0 then | |
btabv[offset] = h | |
search:plus() | |
add = 1 | |
else | |
btabv[offset] = h | |
end | |
else | |
btabv[offset] = 0 | |
add = 0 | |
search:minus() | |
end | |
loop = loop + 1 | |
end | |
end | |
function search:minus() | |
-- decrement the offset | |
local x = 1 | |
while x == 1 do | |
offset = offset - 1 | |
if offset == 0 then | |
return | |
end | |
if btabs[offset] ~= 1 then | |
x = 0 | |
end | |
end | |
end | |
function search:plus() | |
-- increment the offset | |
local x = 1 | |
while x == 1 do | |
offset = offset + 1 | |
if offset > 81 then | |
return | |
end | |
if btabs[offset] ~= 1 then | |
x=0 | |
end | |
end | |
end | |
--# tables | |
tables = class() | |
function tables:set() | |
-- set values in the 9x9 table | |
local x | |
for x=1,81 do | |
btabs[x] = 0 | |
btabv[x] = 0 | |
end | |
end | |
function tables:select() | |
-- set left, right, bottom, top values for the select table | |
local x | |
for x=1,9 do | |
table.insert(stabl,x,50+x*60-29) | |
table.insert(stabr,x,50+x*60+29) | |
table.insert(stabb,x,200-29) | |
table.insert(stabt,x,200+29) | |
end | |
end | |
function tables:board() | |
-- set left, right, bottom, top button values for 9x9 board | |
local x, y | |
local v = 0 | |
for y=9,1,-1 do | |
for x=1,9 do | |
v = v + 1 | |
btabv[v] = "" | |
table.insert(btabl,v,50+x*60-29) | |
table.insert(btabr,v,50+x*60+29) | |
table.insert(btabb,v,250+y*60-29) | |
table.insert(btabt,v,250+y*60+29) | |
end | |
end | |
end | |
function tables:buttons() | |
-- set left, right, bottom, top values for the buttons | |
bstart[1] = 100 -- left | |
bstart[2] = 200 -- right | |
bstart[3] = 875 -- bottom | |
bstart[4] = 925 -- top | |
bexit[1] = 300 | |
bexit[2] = 400 | |
bexit[3] = 875 | |
bexit[4] = 925 | |
bpause[1] = 500 | |
bpause[2] = 600 | |
bpause[3] = 875 | |
bpause[4] = 925 | |
end | |
-- end of program |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment