This is type of the callback that performs the Hanoi move. An interface{} could be used here but since no state is being maintained a function type is a better choice.
type ( MoveFunc func(n int, start, end string) )
The Hanoi function. Moves n pegs from start to end using 3 pegs.
func hanoi(n int, pegStart, pegEnd, pegExtra string, mover MoveFunc) {
if n == 1 {
mover(1, pegStart, pegEnd)
} else {
hanoi(n-1, pegStart, pegExtra, pegEnd, mover)
mover(n, pegStart, pegEnd)
hanoi(n-1, pegExtra, pegEnd, pegStart, mover)
}
}
A basic moving function. Simply prints out the actual move (e.g. Move disk 2 from "A" to "C").
func move(n int, start, end string) {
fmt.Printf("Move disk %d from %q to %q.\n", n, start, end)
}
Kicks of the process for 4 disks.
func main() {
hanoi(4, "A", "B", "C", move)
}
This function constructs a MoveFunc function that wraps around an actual move function. The idea here is to check if certain invariants hold before each move.
func checkmove(n int, peg string, move MoveFunc) MoveFunc {
position := make([]string, n+1)
for i := 1; i < len(position); i++ {
position[i] = peg
}
return func(n int, start, end string) {
if n < 1 || n > len(position)-1 {
panic(fmt.Sprintf("Bad disk number %d, should be 1..%d", n, len(position)-1))
}
if position[n] != start {
panic(fmt.Sprintf("Tried to move disk %d from %q, but it is on peg %q", n, start, position[n]))
}
for i := 1; i < n-1; i++ {
if position[i] == start {
panic(fmt.Sprintf("Can't move disk %n from %q because %n is on top of it", n, start, i))
} else if position[i] == end {
panic(fmt.Sprintf("Can't move disk %n to %q becasue %n is already there", n, end, i))
}
}
move(n, start, end)
position[n] = end
}
}
Again, kicking of the process for 4 disks, now using the wrapper to construct the invariant function around the mover.
func main() {
hanoi(4, "A", "B", "C", checkmove(4, "A", move))
}
Get the source at GitHub
No comments:
Post a Comment