Had you ever imagined you can write a Sudoku game in just 162 lines of coding? HMG made it possible.
Believe me, it took only an hour of my life.
Though it is not a solver by itself, you can play the game. This is the initial version. Give your suggestions to improve.
Code: Select all
#include <hmg.ch>
Function Main
local bColor
private aSudoku := {{0,0,0,2,0,3,8,0,1},;
{0,0,0,7,0,6,0,5,2},;
{2,0,0,0,0,0,0,7,9},;
{0,2,0,1,5,7,9,3,4},;
{0,0,3,0,0,0,1,0,0},;
{9,1,7,3,8,4,0,2,0},;
{1,8,0,0,0,0,0,0,6},;
{7,3,0,6,0,1,0,0,0},;
{6,0,5,8,0,9,0,0,0}}
private aOriginal := {}
bColor := {||SudokuBackcolor()}
aOriginal := aclone(aSudoku)
define window Sudoku at 0,0 width 500 height 550 main title "HMG Sudoku"
define grid square
row 10
col 10
width 460
height 445
showheaders .f.
headers {"","","","","","","","",""}
widths {50,50,50,50,50,50,50,50,50}
justify {2,2,2,2,2,2,2,2,2}
allowedit .t.
columncontrols {{"TEXTBOX","CHARACTER","9"},{"TEXTBOX","CHARACTER","9"},{"TEXTBOX","CHARACTER","9"},{"TEXTBOX","CHARACTER","9"},{"TEXTBOX","CHARACTER","9"},{"TEXTBOX","CHARACTER","9"},{"TEXTBOX","CHARACTER","9"},{"TEXTBOX","CHARACTER","9"},{"TEXTBOX","CHARACTER","9"}}
fontsize 30
dynamicbackcolor {bColor,bColor,bColor,bColor,bColor,bColor,bColor,bColor,bColor}
columnwhen {{||entergrid()},{||entergrid()},{||entergrid()},{||entergrid()},{||entergrid()},{||entergrid()},{||entergrid()},{||entergrid()},{||entergrid()}}
columnvalid {{||checkgrid()},{||checkgrid()},{||checkgrid()},{||checkgrid()},{||checkgrid()},{||checkgrid()},{||checkgrid()},{||checkgrid()},{||checkgrid()}}
onchange checkpossiblevalues()
fontname "Arial"
cellnavigation .t.
end grid
define label valid
row 460
col 10
fontname "Arial"
width 480
fontsize 18
end label
end window
on key ESCAPE of Sudoku action Sudoku.release()
refreshsudokugrid()
sudoku.center
sudoku.activate
Return nil
function SudokuBackColor
do case
case this.cellrowindex <= 3 // first row
do case
case this.cellcolindex <= 3 // first col
return {200,100,100}
case this.cellcolindex > 3 .and. this.cellcolindex <= 6// second col
return {100,200,100}
case this.cellcolindex > 6 // third col
return {100,100,200}
endcase
case this.cellrowindex > 3 .and. this.cellrowindex <= 6 // second row
do case
case this.cellcolindex <= 3 // first col
return {100,200,100}
case this.cellcolindex > 3 .and. this.cellcolindex <= 6// second col
return {200,200,100}
case this.cellcolindex > 6 // third col
return {100,200,100}
endcase
case this.cellrowindex > 6 // third row
do case
case this.cellcolindex <= 3 // first col
return {100,100,200}
case this.cellcolindex > 3 .and. this.cellcolindex <= 6// second col
return {100,200,100}
case this.cellcolindex > 6 // third col
return {200,100,100}
endcase
endcase
return nil
function refreshsudokugrid
local i := 0
local aLine := {}
local aValue := sudoku.square.value
sudoku.square.deleteallitems()
if len(aSudoku) == 9
for i := 1 to len(aSudoku)
asize(aLine,0)
for j := 1 to len(aSudoku[i])
if aSudoku[i,j] > 0
aadd(aLine,str(aSudoku[i,j],1,0))
else
aadd(aLine,'')
endif
next j
sudoku.square.additem(aLine)
next i
endif
sudoku.square.value := aValue
return nil
function entergrid
local aValue := sudoku.square.value
if len(aValue) > 0
if aOriginal[aValue[1],aValue[2]] > 0
return .f.
else
return .t.
endif
endif
return .f.
function checkgrid
local nRow := this.cellrowindex
local nCol := this.cellcolindex
local nValue := val(alltrim(this.cellvalue))
local aLine := {}
local i := 0
local j := 0
local nRowStart := (int((nRow-1)/3) * 3) + 1
local nRowEnd := nRowstart + 2
local nColStart := (int((nCol-1)/3) * 3) + 1
local nColEnd := nColstart + 2
if nValue == 0
this.cellvalue := ''
sudoku.valid.value := ''
aSudoku[nRow,nCol] := 0
return .t.
endif
for i := 1 to 9
if aSudoku[nRow,i] == nValue //row checking
return .f.
endif
if aSudoku[i,nCol] == nValue //col checking
return .f.
endif
next i
for i := nRowStart to nRowEnd
for j := nColStart to nColEnd
if aSudoku[i,j] == nValue
return .f.
endif
next j
next i
sudoku.valid.value := ''
aSudoku[nRow,nCol] := nValue
checkcompletion()
return .t.
function checkcompletion
for i := 1 to len(aSudoku)
for j := 1 to len(aSudoku[i])
if aSudoku[i,j] == 0
return nil
endif
next j
next i
msginfo("Congrats! You won!")
return nil
function checkpossiblevalues
local aValue := sudoku.square.value
local aAllowed := {}
local cAllowed := ""
local nRowStart := (int((aValue[1]-1)/3) * 3) + 1
local nRowEnd := nRowstart + 2
local nColStart := (int((aValue[2]-1)/3) * 3) + 1
local nColEnd := nColstart + 2
local lAllowed := .t.
local i := 0
local j := 0
local k := 0
if aValue[1] > 0 .and. aValue[2] > 0
if aOriginal[aValue[1],aValue[2]] > 0
sudoku.valid.value := ""
return nil
else
for i := 1 to 9
lAllowed := .t.
for j := 1 to 9
if aSudoku[aValue[1],j] == i
lAllowed := .f.
endif
if aSudoku[j,aValue[2]] == i
lAllowed := .f.
endif
next j
for j := nRowStart to nRowEnd
for k := nColStart to nColEnd
if aSudoku[j,k] == i
lAllowed := .f.
endif
next k
next j
if lAllowed
aadd(aAllowed,i)
endif
next i
if len(aAllowed) > 0
for i := 1 to len(aAllowed)
if i == 1
cAllowed := cAllowed + alltrim(str(aAllowed[i]))
else
cAllowed := cAllowed + ", "+ alltrim(str(aAllowed[i]))
endif
next i
sudoku.valid.value := "Possible Numbers: "+cAllowed
else
sudoku.valid.value := "Possible Numbers: Nil"
endif
return nil
endif
endif
return nil