Can someone give me advice on how to create a recursive version of GetEnumerator ()? The famous Towers of Hanoi problem can be an example comparable to the actual problem that I have. A simple algorithm for displaying all moves for a stack of disks with height n is:
void MoveTower0 (int n, Needle start, Needle finish, Needle temp) { if (n > 0) { MoveTower0 (n - 1, start, temp, finish); Console.WriteLine ("Moving disk from {0} to {1}", start, finish); MoveTower0 (n - 1, temp, finish, start); } }
Actually, I want to create a HanoiTowerMoves class that implements IEnumerable and allows me to iterate over all the moves as follows:
foreach (Move m in HanoiTowerMoves) Console.WriteLine (m);
The first step to implementing GetEnumerator () seems to be getting rid of the MoveTower parameters. This can be easily done using the stack. I also introduced the Move class, which combines parameters into one variable.
class Move { public int N { private set; get; } public Needle Start { private set; get; } public Needle Finish { private set; get; } public Needle Temp { private set; get; } public Move (int n, Needle start, Needle finish, Needle temp) { N = n; Start = start; Finish = finish; Temp = temp; } public override string ToString () { return string.Format ("Moving disk from {0} to {1}", Start, Finish); } }
Now MoveTower can be rewritten as follows:
void MoveTower1 () { Move m = varStack.Pop (); if (mN > 0) { varStack.Push (new Move (mN - 1, m.Start, m.Temp, m.Finish)); MoveTower1 (); Console.WriteLine (m); varStack.Push (new Move (mN - 1, m.Temp, m.Finish, m.Start)); MoveTower1 (); } }
This version should be called as follows:
varStack.Push (new Move (n, Needle.A, Needle.B, Needle.Temp)); MoveTower1 ();
The next step to the iterable version is to implement the class:
class HanoiTowerMoves : IEnumerable<Move> { Stack<Move> varStack; int n; // number of disks public HanoiTowerMoves (int n) { this.n = n; varStack = new Stack<Move> (); } public IEnumerator<Move> GetEnumerator () { // ???????????????????????????? } // required by the compiler: IEnumerator IEnumerable.GetEnumerator () { return GetEnumerator (); } }
Now for me the big question is: what does the body of GetEnumerator () look like? Can anyone solve this mystery for me?
The following is the Program.cs code of the console application I created.
using System; using System.Collections.Generic; using System.Collections; /* Towers of Hanoi * =============== * Suppose you have a tower of N disks on needle A, which are supposed to end up on needle B. * The big picture is to first move the entire stack of the top N-1 disks to the Temp needle, * then move the N-th disk to B, then move the Temp stack to B using A as the new Temp needle. * This is reflected in the way the recursion is set up. */ namespace ConsoleApplication1 { static class main { static void Main (string [] args) { int n; Console.WriteLine ("Towers of Hanoi"); while (true) { Console.Write ("\r\nEnter number of disks: "); if (!int.TryParse (Console.ReadLine (), out n)) { break; } HanoiTowerMoves moves = new HanoiTowerMoves (n); moves.Run (1); // algorithm version number, see below } } } class Move { public int N { private set; get; } public Needle Start { private set; get; } public Needle Finish { private set; get; } public Needle Temp { private set; get; } public Move (int n, Needle start, Needle finish, Needle temp) { N = n; Start = start; Finish = finish; Temp = temp; } public override string ToString () { return string.Format ("Moving disk from {0} to {1}", Start, Finish); } } enum Needle { A, B, Temp } class HanoiTowerMoves : IEnumerable<Move> { Stack<Move> varStack; int n; // number of disks public HanoiTowerMoves (int n) { this.n = n; varStack = new Stack<Move> (); } public void Run (int version) { switch (version) { case 0: // Original version MoveTower0 (n, Needle.A, Needle.B, Needle.Temp); break; case 1: // No parameters (ie argument values passed via stack) varStack.Push (new Move (n, Needle.A, Needle.B, Needle.Temp)); MoveTower1 (); break; case 2: // Enumeration foreach (Move m in this) { Console.WriteLine (m); } break; } } void MoveTower0 (int n, Needle start, Needle finish, Needle temp) { if (n > 0) { MoveTower0 (n - 1, start, temp, finish); Console.WriteLine ("Moving disk from {0} to {1}", start, finish); MoveTower0 (n - 1, temp, finish, start); } } void MoveTower1 () { Move m = varStack.Pop (); if (mN > 0) { varStack.Push (new Move (mN - 1, m.Start, m.Temp, m.Finish)); MoveTower1 (); Console.WriteLine (m); varStack.Push (new Move (mN - 1, m.Temp, m.Finish, m.Start)); MoveTower1 (); } } public IEnumerator<Move> GetEnumerator () { yield break; // ???????????????????????????? } /* void MoveTower1 () { Move m = varStack.Pop (); if (mN > 0) { varStack.Push (new Move (mN - 1, m.Start, m.Temp, m.Finish)); MoveTower1 (); Console.WriteLine (m); ? yield return m; varStack.Push (new Move (mN - 1, m.Temp, m.Finish, m.Start)); MoveTower1 (); } } */ // required by the compiler: IEnumerator IEnumerable.GetEnumerator () { return GetEnumerator (); } } }