uniquename 2013aug18For readers who do not have the time/facilities/whatever to setup and run the following code, here is an image to show the nice quality of the crossword grid that is produced. This image shows the American style layout. As the description above indicates, the British and Japanese layouts have more black squares than the American --- and fewer squares in the case of Japanese layouts.
##+########################################################################## # # Crossword Puzzle Builder # by Keith Vetter, February 2006 # package require Tk catch {package require tile} ;# Use tile if available catch {namespace import -force ::ttk::button} array set S {title "Crossword Puzzle Builder" N 17 W 600 min 5 max 50} array set U {undo {} redo {}} proc DoDisplay {} { wm title . $::S(title) font create myFont -family Helvetica -size 7 canvas .c -bd 2 -relief ridge -width $::S(W) -height $::S(W) bind .c <Configure> {ReCenter %W %h %w} bind .c <Control-n> NewPuzzle bind .c <Control-z> Undo bind .c <Control-y> Redo bind .c <Key-Delete> Clear pack .c -side top -fill both -expand 1 DoMenus DrawGrid focus .c } proc DoMenus {} { . configure -menu [menu .m -tearoff 0] .m add cascade -menu [menu .m.file -tearoff 0] -label "File" -underline 0 .m add cascade -menu [menu .m.edit -tearoff 0] -label "Edit" -underline 0 .m add cascade -menu [menu .m.help -tearoff 0] -label "Help" -underline 0 .m.file add command -label "New" -under 0 -command NewPuzzle -accel "Ctrl+N" .m.file add separator .m.file add command -label "Save Puzzle" -under 0 -state disabled .m.file add command -label "Print" -under 0 -state disabled .m.file add separator .m.file add command -label "Exit" -under 1 -command exit .m.edit add command -label Undo -under 0 -command Undo \ -accel "Ctrl+Z" -state disabled .m.edit add command -label Redo -under 0 -command Redo \ -accel "Ctrl+Y" -state disabled .m.edit add command -label Clear -under 0 -command Clear -accel "Del" .m.help add command -label "American Example" -under 0 -command American .m.help add command -label "British Example" -under 0 -command British .m.help add command -label "Japanese Example" -under 0 -command Japanese .m.help add separator .m.help add command -label About -under 0 -command About } proc ReCenter {W h w} { ;# Called by configure event set h2 [expr {$h / 2}] ; set w2 [expr {$w / 2}] $W config -scrollregion [list -$w2 -$h2 $w2 $h2] Resize } proc Resize {} { set w [winfo width .c] set h [winfo height .c] foreach {x0 y0 x1 y1} [.c bbox all] break set sx [expr {($w-40)/2.0 / $x1}] set sy [expr {($h-40)/2.0 / $y1}] set sc [expr {$sx > $sy ? $sy : $sx}] if {$sc < 0} return .c scale all 0 0 $sc $sc # Scale myFont here??? } proc DrawGrid {} { global S GRID set sz 29 .c delete all unset -nocomplain GRID set x0 [expr {-$S(N) * $sz / 2}] set y0 $x0 for {set row 0} {$row < $S(N)} {incr row} { set GRID(-1,$row) 1 ;# Sentinels set GRID($S(N),$row) 1 set GRID($row,-1) 1 set GRID($row,$S(N)) 1 set y1 [expr {$y0 + $row * $sz}] set y2 [expr {$y1 + $sz}] for {set col 0} {$col < $S(N)} {incr col} { set x1 [expr {$x0 + $col * $sz}] set x2 [expr {$x1 + $sz}] .c create rect $x1 $y1 $x2 $y2 -tag b$row,$col -fill white -outline black .c bind b$row,$col <1> [list BDown $row $col] set GRID($row,$col) 0 } } Renumber Resize } proc BDown {row col {noUndo 0}} { set row2 [expr {$::S(N) - $row - 1}] set col2 [expr {$::S(N) - $col - 1}] set ::GRID($row,$col) [expr {! $::GRID($row,$col)}] set ::GRID($row2,$col2) $::GRID($row,$col) set fill [expr {$::GRID($row,$col) ? "black" : "white"}] .c itemconfig b$row,$col -fill $fill .c itemconfig b$row2,$col2 -fill $fill Renumber if {! $noUndo} { lappend ::U(undo) [list $row $col] set ::U(redo) {} UndoDisplay } } proc Renumber {} { global S GRID .c delete number set n 1 for {set row 0} {$row < $S(N)} {incr row} { set r0 [expr {$row-1}] set r1 [expr {$row+1}] for {set col 0} {$col < $S(N)} {incr col} { if {$GRID($row,$col)} continue set c0 [expr {$col-1}] set c1 [expr {$col+1}] if {($GRID($r0,$col) && ! $GRID($r1,$col)) || ($GRID($row,$c0) && ! $GRID($row,$c1))} { foreach {x y} [.c coords b$row,$col] break set t [.c create text $x $y -text $n -font myFont -anchor nw \ -tag number] .c bind $t <1> [list BDown $row $col] incr n } } } .c move number 2 1 } proc About {} { set ABOUT { This program lets you create grids suitable for both American and British style crossword puzzles. Traditionally, these grids are square with 180-degree rotational symmetry so that its pattern appears the same if the paper is turned upside down. Most puzzle designs also require that all the white cells are connected. American crosswords typically have large chunks of white squares with each answer at least three letters long. Black squares are limited to about one-sixth of the design. British crosswords are more latice-like with a higher percentage of black squares with no two answers being next to each other. British crosswords also differ in their clues which are traditionally very cryptic. Particularly curious is the Japanese language crossword; due to the writing system, one syllable (typically katakana) is entered into each white cell of the grid rather than one letter, resulting in the typical solving grid seeming rather small in comparison to those of other languages. There grids follow two additional rules: black cells cannot share a side, and the corner cells must be white. source: http://en.wikipedia.org/wiki/Crossword_puzzle} regsub -all -line {^[ \t]+} $ABOUT "" ABOUT set msg "$::S(title)\nby Keith Vetter, February 2007\n$ABOUT" tk_messageBox -message $msg -title "About $::S(title)" } image create photo ::img::info -data { R0lGODlhIAAgALMAAAAAAAAA/4SEhMbGxvf/Mf////////////////////////////////////// /////yH5BAEAAAQALAAAAAAgACAAAAStkMhJibj41s0nHkUoDljXXaCoqqRgUkK6zqP7CvQQ7IGs AiYcjcejFYAb4ZAYMB4rMaeO51sNkBKlc/uzRbng0NWlnTF3XAAZzExj2ET3BV7cqufctv2Tj0vv Fn11RndkVSt6OYVZRmeDXRoTAGFOhTaSlDOWHACHW2MlHQCdYFebN6OkVqkZlzcXqTKWoS8wGJMh s7WoIoC7v7i+v7uTwsO1o5HHu7TLtcodEQAAOw==} proc NewPuzzle {{value ""}} { if {$value eq ""} { foreach {ok value} [NewDialog] break if {! $ok} return if {! [string is integer -strict $value]} return if {$value < $::S(min) || $value > $::S(max)} return } set ::S(N) $value DrawGrid set ::U(undo) {} set ::U(redo) {} UndoDisplay } proc NewDialog {} { set W .new destroy $W toplevel $W -padx 20 wm title $W "New Puzzle" wm transient $W . wm withdraw $W label $W.icon -image ::img::info label $W.title -text "New Puzzle" -font "Times 18 bold" label $W.lvalue -text "Size ($::S(min)-$::S(max)): " entry $W.value -width 5 -textvariable ::S(new,value) set ::S(new,value) $::S(N) frame $W.buttons button $W.ok -text OK -command "set ::S(new,ok) 1; destroy $W" button $W.cancel -text Cancel -command [list destroy $W] set ::S(new,ok) 0 grid $W.icon $W.title - - grid ^ $W.lvalue $W.value grid $W.buttons - - - -sticky ew -pady {30 10} grid $W.ok $W.cancel -in $W.buttons -padx 4 -sticky ew grid columnconfigure $W.buttons {0 1} -uniform a grid columnconfigure $W 3 -weight 1 grid configure $W.icon -padx {0 20} grid configure $W.lvalue -sticky e grid configure $W.value -sticky w focus $W.value $W.value icursor end $W.value selection range 0 end bind $W.value <Key-Return> [list $W.ok invoke] CenterWindow $W . wm deiconify $W grab $W tkwait window $W return [list $::S(new,ok) $::S(new,value)] } proc CenterWindow {w {W .}} { set x [expr {[winfo x $W] + \ ([winfo width $W]-[winfo reqwidth $w])/2}] set y [expr {[winfo y $W] + \ ([winfo height $W]-[winfo reqheight $w])/2}] wm geometry $w +$x+$y } proc Undo {} { global U if {$U(undo) eq {}} return set move [lindex $U(undo) end] set U(undo) [lrange $U(undo) 0 end-1] lappend U(redo) $move foreach {row col} $move { BDown $row $col 1 } UndoDisplay } proc UndoDisplay {} { .m.edit entryconfig Undo -state [expr {$::U(undo) eq {} ? "disabled" : "normal"}] .m.edit entryconfig Redo -state [expr {$::U(redo) eq {} ? "disabled" : "normal"}] } proc Redo {} { global U if {$U(redo) eq {}} return set move [lindex $U(redo) end] set U(redo) [lrange $U(redo) 0 end-1] lappend U(undo) $move foreach {row col} $move { BDown $row $col 1 } UndoDisplay } proc Clear {} { global S GRID set N2 [expr {$S(N)/2}] set undo {} for {set row 0} {$row <= $N2} {incr row} { set row2 [expr {$S(N) - $row - 1}] for {set col 0} {$col < $S(N)} {incr col} { if {$GRID($row,$col)} { set col2 [expr {$S(N) - $col - 1}] set GRID($row,$col) 0 set GRID($row2,$col2) 0 .c itemconfig b$row,$col -fill white .c itemconfig b$row2,$col2 -fill white lappend undo $row $col } } } Renumber if {$undo ne {}} {lappend ::U(undo) $undo} UndoDisplay } proc American {} { NewPuzzle 17 foreach {row col} {0 7 0 12 1 7 1 12 2 7 3 0 3 1 3 8 3 13 4 4 4 8 4 9 4 10 4 15 4 16 5 5 5 6 6 3 6 11 7 7 7 12 8 0 8 1 8 2} { BDown $row $col } } proc British {} { NewPuzzle 15 foreach {row col} {1 0 3 0 5 0 7 0 7 1 7 2 9 1 9 2 11 1 13 1 1 2 1 4 0 4 1 6 1 7 1 9 1 11 3 2 5 2 3 4 5 4 7 4 3 6 3 7 5 6 6 6 7 6 3 11 3 9 4 9 5 8 5 10} { BDown $row $col } } proc Japanese {} { NewPuzzle 9 foreach {row col} {0 4 1 3 2 2 3 1 7 0 6 1 5 2 6 3 4 4} { BDown $row $col } } DoDisplay American return