#!/usr/local/bin/wish
#fifteen puzzle with arbitrary number of sides

set n 4
set m 4


bind . <space> "Reset"
bind . <Return> "Scramble"



proc Reset {} {
global n m
for {set i 0} {$i < 200} {incr i} {
if {[winfo exists .b$i]} {
destroy .b$i
}}
for {set i 0} {$i < [expr {$n*$m}]} {incr i} {
if {$i < [expr {$n*$m - 1}]} {
set j [expr {$i + 1}]
} else {
set j 0
}
button .b$i -text $j -height 2 -width 2 -command "Do $i"
grid .b$i -row [expr {$i/$m}] -column [expr {$i%$m}]
}
if {[winfo exists .f]} {
destroy .f
set i 0
foreach p {l e1 e2 r d s} {
destroy .f.$p
incr i
}
}
frame .f
grid .f -row $n -column 0 -columnspan 10
label .f.l -text "dimensions:"
entry .f.e1 -width 3 -textvariable n
entry .f.e2 -width 3 -textvariable m
button .f.r -text "reset" -command Reset
button .f.d -text "dismiss" -command "destroy ."
button .f.s -text "scramble" -command Scramble
set i 0
foreach p {l e1 e2 r d s} {
grid .f.$p -row [expr $n + $i/3] -column [expr 2*($i%3)] -columnspan 2
incr i
}
}

proc Do {i} {
global m n
if {[expr {$i/$m}] != 0 && [.b[expr {$i - $m}] cget -text]== 0} {
.b[expr {$i - $m}]  configure -text [.b$i cget -text]
.b$i configure -text 0
} elseif {[expr {$i/$m + 1 - $n}] != 0 && [.b[expr {$i + $m}] cget -text]== 0} {
.b[expr {$i + $m}]  configure -text [.b$i cget -text]
.b$i configure -text 0
} elseif {[expr {$i%$m + 1 - $m}] != 0 && [.b[expr {$i + 1}] cget -text] == 0} {
.b[expr {$i + 1}] configure -text [.b$i cget -text]
.b$i configure -text 0
} elseif {[expr {$i%$m}] != 0 && [.b[expr {$i - 1}] cget -text] == 0} {
.b[expr {$i - 1}] configure -text [.b$i cget -text]
.b$i configure -text 0
}
}

proc Scramble {} {
global m n
Do [expr $m*$n - 1]
for {set i 1} {$i < 100} {incr i} {
set k [expr int(rand()*$n*$m)]
Do $k
}
}

Reset

