#!/usr/local/bin/wish

# Create the two control buttons Reset and Restart 
# Reset starts puzzle anew; restart goes back to the original
# configuration of the puzzle.

button .reset -text "Reset" -command Reset
button .restart -text "Restart" -command Restart

# Set the number of colors nc to 3 (in other versions of the puzzle
# this number can be changed by the user but not in this one).

set nc 3

# Put the button in place

grid .reset -row 0 -column 0 -columnspan 1 
grid .restart -row 0 -column 1 -columnspan 1

# Set the number h of buttons to 6.

set h 6

# Set the list of allowable colors

set colors {"white" "red" "blue" "green" "yellow"}

# Give the vertical and horizontal coordinates of the location of the
# buttons 

set vert {2  1 1 2 3 3}
set horiz {4 3 1 0 1 3 }

# Set moves to a list whose i-th item is itself a list with the effect
# on the colors of all buttons when clicking i-th button. I.e. moves
# is really the matrix A describing the puzzle written as a list of
# its columns c_1, c_2, ..., c_h.

set moves {{0 1 0 0 0 1} {1 0 1 0 0 0} {0 1 0 1 0 0} {0 0 1 0 1 0} {0 0 0 1 0 1} {1 0 0 0 1 0}}

#  The procedure Set will display the buttons in place with color
#  given by the function v.

proc Set {} {
global h  v  colors vert horiz

# First destroy buttons...

for {set i 1} {$i <= h} {incr i} {
if {[winfo exists .b$i]} {
destroy .b$i
}   }   

#  and then create them again.

for {set i 1} {$i <= $h} {incr i} {

set color [lindex $colors $v($i)]

# Associate the command Do($i) to the i-th button.

button .b$i -height 5 -width 10 -relief raised -background $color -activebackground $color -command "Do $i"

grid .b$i -row [lindex $vert [expr $i -1]] -column [lindex $horiz [expr $i -1]]

}
}

# The process Do{i} is attached to the i-th button. In effect does the
# linear algebra move v |---> v + c_i mod nc.

proc Do {i} {
global v moves nc h

for {set j 1} {$j <= $h} {incr j} {

set v($j) [expr ([lindex [lindex $moves [expr $i -1]] [expr $j -1]]+$v($j))%$nc]
}

# After changing the colors we need to redisplay the buttons.

Set

}

# Go back to original (random) configuration.

proc Restart {} {
global h w v  colors vert horiz nc

# Destroy buttons

for {set i 1} {$i <= 20} {incr i} {
if {[winfo exists .b$i]} {
destroy .b$i
}   }   

# Recover original colors stored in function w.

for {set i 1} {$i <= $h} {incr i} {

    set v($i) $w($i)

# Redisplay new button colors.

Set
}
}

# Start puzzle from scratch picking random colors.

proc Reset {} {
global h w v  colors vert horiz nc

# Destroy buttons

for {set i 1} {$i <= 20} {incr i} {
if {[winfo exists .b$i]} {
destroy .b$i
}   }   

# Get new colors.

for {set i 1} {$i <= $h} {incr i} {

# Get a random color for the $i-th cell

    set v($i) [expr {round($nc*rand()-.5)}]

# Store original position in w to use by function Restart.

    set w($i) $v($i)

}

# Redisplay buttons.

Set
}

# Once all declarations are done we need to start the puzzle the first
# time around.

Reset

