Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Towers of Hanoi: Moving Rings from Peg to Peg

Expanding on my previous post, I am still writing Towers of Hanoi. After having a wonderful solution explained of how to draw the rings on the pegs, I still have one question that I have been fiddling with for quite awhile now.

Here is my PegClass:

namespace Towers_Of_Hanoi
{
    class PegClass
    {
        private int pegheight; 
        private int y = 3;
        int[] rings = new int[0];
        public PegClass()
        { 
            //this is the default constructor 
        }
        public PegClass(int height)
        { 
            pegheight = height; 
        }

        // other user defined functions 
        public void AddRing(int size)
        { 
            Array.Resize (ref rings, rings.Length + 2);
            rings[rings.Length - 1] = size;
        }

        public void DrawPeg(int x, int numberOfRings = 0)
        { 
            for (int i = pegheight; i >= 1; i--) 
            {
                string halfRing = new string (' ', i);
                if (numberOfRings > 0) 
                { 
                    if (i <= numberOfRings)
                        halfRing = new string ('-', numberOfRings - i + 1);

                }
                Console.SetCursorPosition(x - halfRing.Length * 2 + i + (halfRing.Contains("-") ? (-i + halfRing.Length) : 0), y);
                Console.WriteLine(halfRing + "|" + halfRing);
                y++;
            }
            if (x < 7) {
                x = 7;
            }
            Console.SetCursorPosition (x - 7, y); //print the base of the peg
            Console.WriteLine("----------------");
        }
    }
}

And here is my main method.

namespace Tower_of_hanoi
{
    class Program
    {
        static void Main(string[] args)
        {
            PegClass myPeg = new PegClass(8);
            PegClass myPeg2 = new PegClass(8);
            PegClass myPeg3 = new PegClass(8);
            DrawBoard(myPeg, myPeg2, myPeg3);
            Console.WriteLine ("\t\t\nWelcome to kTowers!");

            while (true) 
            {
                string input = "\nWhat peg do you want to move to commander?";
                Console.WriteLine (input);
                if (input == "2")
                {
                    myPeg.DrawPeg (2);
                }
                Console.ReadLine ();          
            }
        }

        public static void DrawBoard(PegClass peg1,PegClass peg2,PegClass peg3)
        {
            Console.Clear();
            peg1.DrawPeg(20,1);
            peg2.DrawPeg(40,2);
            peg3.DrawPeg(60,4);
        }
    }
}

This is the current output:

                |                   |                   |        
                |                   |                   |       
                |                   |                   |      
                |                   |                   |     
                |                   |                  -|-
                |                   |                 --|--
                |                  -|-               ---|---
               -|-                --|--             ----|----
         ----------------    ----------------    ----------------

My question remains, how does one move the '-' characters from peg to peg when asked for a prompt. I've tried tweaking it for hours and still couldn't figure it out.

Thank you in advance, youmeoutside

like image 542
youmeoutside Avatar asked Jan 08 '16 04:01

youmeoutside


People also ask

Which of the rule for the Tower of Hanoi is correct?

Rules. Only one disk can be moved among the towers at any given time. Only the "top" disk can be removed. No large disk can sit over a small disk.

What is peg in Tower of Hanoi?

The full Tower of Hanoi solution then consists of moving n disks from the source peg A to the target peg C, using B as the spare peg. This approach can be given a rigorous mathematical proof with mathematical induction and is often used as an example of recursion when teaching programming.

How many steps will it take to move 4 disks in Towers of Hanoi?

In this formula, S is the number of steps, and N is the number of discs. So, if the tower had five discs, the formula would be 25-1, which is 31. Therefore, solving the puzzle would take a minimum of 31 steps. If it had four discs, it would require only 15 steps – and for three discs, only 7.


1 Answers

You have manifested the rings as just "how many rings are on this peg" but that won't be enough.

For instance, if you have 8 rings you will represent one ring with width 1, one with width 2, one with 3, etc. up to one with 8.

In your image you have 3 rings with width of 1 (the top one on each peg), 2 with width 2 (the second ring on the two pegs that have multiple rings), and so on. This is incorrect and the reason for why your code does this is that it have no notion of "how wide should this particular ring be", instead it draws the top ring with width 1, the one below it with width 2, etc.

Instead here is a very simple set of objects to represent the rings and pegs and the operation to move from one to the other:

public void MoveRing(Peg fromPeg, Peg toPeg)
{
    toPeg.Push(fromPeg.Pop());
}

public class Peg : Stack<Ring>
{
}

public struct Ring
{
    public int Width { get; }
    public Ring(int width) { Width = width; }
}

To create 3 pegs and stack 8 rings on the first peg you could use this code:

const int pegCount = 3;
const int ringCount = 8;

var pegs = Enumerable.Range(1, pegCount).Select(_ => new Peg()).ToList();

foreach (var ring in Enumerable.Range(1, ringCount).Select(width => new Ring(ringCount + 1 - width)))
    pegs[0].Push(ring);

To draw them I took the liberty of fleshing out a LINQPad program that draws them to demonstrate but you could easily adapt this to the console code you have now:

void Main()
{
    const int pegCount = 3;
    const int ringCount = 8;

    var pegs = Enumerable.Range(1, pegCount).Select(_ => new Peg()).ToList();

    foreach (var ring in Enumerable.Range(1, ringCount).Select(width => new Ring(ringCount + 1 - width)))
        pegs[0].Push(ring);

    DrawPegs(pegs);
    MoveRing(pegs[0], pegs[1]);
    DrawPegs(pegs);
}

public void MoveRing(Peg fromPeg, Peg toPeg)
{
    toPeg.Push(fromPeg.Pop());
}

public class Peg : Stack<Ring>
{
}

public struct Ring
{
    public int Width { get; }
    public Ring(int width) { Width = width; }
}

public void DrawPegs(IEnumerable<Peg> pegs)
{
    var bitmaps = pegs.Select(peg => DrawPeg(peg));
    Util.HorizontalRun(true, bitmaps).Dump();
}

public Bitmap DrawPeg(Peg peg)
{
    const int width = 200;
    const int height = 300;
    const int pegWidth = 6;
    const int ringHeight = 20;
    const int ringWidthFactor = 10;
    const int ringGapHeight = 3;

    var result = new Bitmap(width, height);
    using (var g = Graphics.FromImage(result))
    {
        g.Clear(Color.White);

        g.FillRectangle(Brushes.Black, width / 2 - pegWidth/2, 0, pegWidth, height);
        int y = height;
        foreach (var ring in peg.Reverse())
        {
            y -= ringHeight;
            g.FillRectangle(Brushes.Blue, width / 2 - ring.Width * ringWidthFactor, y, 2 * ring.Width * ringWidthFactor, ringHeight);
            y -= ringGapHeight;
        }
    }
    return result;
}

The output:

pegs and rings

like image 57
Lasse V. Karlsen Avatar answered Oct 15 '22 12:10

Lasse V. Karlsen