wdb This is a minimalistic Sudoku without bells & whistles [L1 ]. No Menu. No Help. No Game restart after finishing.
#! /usr/bin/env wish if false { package require Tcl 8.5 package require Tk pack\ [canvas .ch -width 270 -height 30 -bg white]\ [canvas .c -width 270 -height 270 -bg white]\ -side bottom wm title . Sudoku proc aloud args { # debugging purposes puts $args uplevel 1 $args } apply {{c ch} { set font {Helvetica -25} set cursorColor grey $c delete all $ch delete all for {set i 0} {$i < 9} {incr i} { for {set j 0} {$j < 9} {incr j} { $c create text [+ [* $i 30] 15] [+ [* $j 30] 15]\ -tags [list nr $i/$j col$i row$j]\ -font $font -text "" -fill grey } } $c create text 0 0 -font $font -fill $cursorColor -tags cursor $c bind cursor <1> [list tryCoords $c %x %y] $c bind cursor <ButtonRelease> [subst { $c itemconfigure nr -fill grey $c itemconfigure cursor -fill $cursorColor $c itemconfigure fixed -fill black }] for {set i 1} {$i < 9} {incr i} { set w [expr {$i % 3 ? 1 : 2}] $c create line [* $i 30] 0 [* $i 30] 270 -width $w -fill grey $c create line 0 [* $i 30] 270 [* $i 30] -width $w -fill grey } for {set i 1} {$i <= 9} {incr i} { $ch create text [- [* $i 30] 15] 15\ -text $i -font $font -tags try$i -fill grey $ch bind try$i <1> [list setNrCursor $c $i] } bind $ch <Shift-1> [list setNrCursor $c ""] bind $ch <Control-1> [list setNrCursor $c ""] } ::tcl::mathop} .c .ch proc setNr {canvas x y nr} { $canvas itemconfigure $x/$y -text $nr } proc setNrCursor {canvas nr} { if {$nr eq ""} then { $canvas configure -cursor "" $canvas itemconfigure cursor -text "" $canvas bind cursor <Motion> "" bind $canvas <Leave> "" bind $canvas <Enter> "" } else { $canvas configure -cursor none bind $canvas <Motion> [list $canvas coords cursor %x %y] bind $canvas <Enter> [list $canvas itemconfigure cursor -text $nr] bind $canvas <Leave> [list $canvas itemconfigure cursor -text ""] } } proc tryCoords {canvas xCoord yCoord} { set x [expr {$xCoord / 30}] set y [expr {$yCoord / 30}] if {"fixed" in [$canvas gettags $x/$y]} then { setNrCursor $canvas [$canvas itemcget $x/$y -text] after idle [list event generate $canvas <Enter>] return } set nr [$canvas itemcget cursor -text] if {[$canvas itemcget $x/$y -text] eq $nr} then { $canvas itemconfigure nr&&$x/$y&&!fixed -text "" return } set occurrences [concat\ [colOccurrence $canvas $x $nr]\ [rowOccurrence $canvas $y $nr]\ [squareOccurrence $canvas $x $y $nr]] if {$occurrences eq ""} then { $canvas itemconfigure nr&&$x/$y&&!fixed\ -text [$canvas itemcget cursor -text] return $nr } # error foreach {x y} $occurrences { $canvas itemconfigure $x/$y -fill red } $canvas itemconfigure cursor -fill red } proc colOccurrence {canvas x nr} { set result {} foreach item [$canvas find withtag col$x] { set text [$canvas itemcget $item -text] if {$text eq $nr} then { set tags [$canvas gettags $item] set index [lsearch $tags row*] set tag [lindex $tags $index] lappend result $x [string index $tag end] } } set result } proc rowOccurrence {canvas y nr} { set result {} foreach item [$canvas find withtag row$y] { set text [$canvas itemcget $item -text] if {$text eq $nr} then { set tags [$canvas gettags $item] set index [lsearch $tags col*] set tag [lindex $tags $index] lappend result [string index $tag end] $y } } set result } proc squareOccurrence {canvas x y nr} { if {$x < 3} then { set xRange {0 1 2} } elseif {$x < 6} then { set xRange {3 4 5} } else { set xRange {6 7 8} } if {$y < 3} then { set yRange {0 1 2} } elseif {$y < 6} then { set yRange {3 4 5} } else { set yRange {6 7 8} } # set result {} foreach i $xRange { foreach j $yRange { set text [$canvas itemcget $i/$j -text] if {$text eq $nr} then { lappend result $i $j } } } set result } proc collides? {canvas x y nr} { expr {[llength\ [concat\ [colOccurrence $canvas $x $nr]\ [rowOccurrence $canvas $y $nr]\ [squareOccurrence $canvas $x $y $nr]]] ? yes : no} } proc inc9 _nr { upvar $_nr nr set nr [expr {int($nr) % 9 + 1}] } proc startRand9 {} { expr {1 + int(rand() * 9)} } proc nextField {x y} { incr x if {$x > 8} then { set x 0 incr y } list $x $y } proc checkField {canvas {x 0} {y 0}} { if {$y > 8} then { return yes } lassign [nextField $x $y] x1 y1 set nr [startRand9] foreach i {1 2 3 4 5 6 7 8 9} { inc9 nr if {[collides? $canvas $x $y $nr]} then continue setNr $canvas $x $y $nr if {[checkField $canvas $x1 $y1]} then { return yes } else { setNr $canvas $x $y "" } } setNr $canvas $x $y "" return no } proc randomly? {} { expr {rand() > 0.5 ? yes : no} } apply {canvas { foreach i {0 1 2 3 4 5 6 7 8} { foreach j {0 1 2 3 4 5 6 7 8} { $canvas itemconfigure $i/$j -text "" } } checkField $canvas foreach i {0 1 2 3 4 5 6 7 8} { foreach j {0 1 2 3 4 5 6 7 8} { if {[randomly?]} then { aloud $canvas addtag fixed withtag $i/$j } else { aloud $canvas dtag $i/$j fixed $canvas itemconfigure $i/$j -text "" } } } $canvas itemconfigure fixed -fill black }} .c
I've hacked it yesterday afternoon (GUI) and this morning (logics).
Have fun.
LV 2009 Aug 12 So, is this program's intent only to display the sudoku board itself? I was trying to figure out how to enter in the numbers to solve the puzzle but I haven't figured it out yet.
wdb Click on the numbers in lower-most row. Then the cursor disappears, instead a number is moved by mouse as a quasi-cursor.