c# - 汉诺塔 : Moving Rings from Peg to Peg

标签 c# .net windows console

扩展我之前的帖子,我还在写汉诺塔。在解释了如何在钉子上画环的绝妙解决方案之后,我仍然有一个问题,我已经摆弄了很长一段时间了。

这是我的 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("----------------");
        }
    }
}

这是我的主要方法。

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);
        }
    }
}

这是当前输出:

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

我的问题仍然存在,当被要求提示时,如何将“-”字符从一个 peg 移动到另一个 peg。我已经尝试调整它几个小时,但仍然无法弄清楚。

提前谢谢你,youmeoutside

最佳答案

您已经将环显化为“这个钉子上有多少个环”,但这还不够。

例如,如果您有 8 个环,您将代表一个宽度为 1 的环、一个宽度为 2 的环、一个宽度为 3 的环,等等,直到一个宽度为 8。

在您的图像中,您有 3 个环,宽度为 1(每个柱子上最上面的一个),宽度为 2 的 2 个环(两个柱子上的第二个环有多个环),依此类推。这是不正确的,您的代码这样做的原因是它没有“这个特定环应该有多宽”的概念,而是绘制宽度为 1 的顶部环,其下方的宽度为 2 等。

取而代之的是一组非常简单的对象来表示环和钉以及从一个移动到另一个的操作:

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; }
}

要创建 3 个钉子并在第一个钉子上堆叠 8 个环,您可以使用以下代码:

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);

为了绘制它们,我冒昧地充实了一个 LINQPad绘制它们进行演示的程序,但您可以轻松地将其调整为您现在拥有的控制台代码:

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;
}

输出:

pegs and rings

关于c# - 汉诺塔 : Moving Rings from Peg to Peg,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34669652/

相关文章:

c#实现带有子类类型参数的接口(interface)方法

c# - 使用c#从json数据中获取值

.net - 即使设置为 Tls12,WCF 也会继续使用 TLS 1.0 和 RSA

c# - 使用正则表达式将长度在 2 到 8 之间的数字替换为特定字符

c# - 在 C# Windows 应用程序中打开我的电脑属性

c# - 如何获取流阅读器的名称

c# - 将图像添加到 pictureBox

C#、MAF、单独 AppDomain 中的未处理异常管理

windows - 为 App Installer 文件设置依赖项

windows - 为什么 spark-shell 失败并显示 "The filename, directory name, or volume label syntax is incorrect."?