前回、大分吹かしましたが、結局ウィンドウプログラムは石盤のビットマップを作らなければならないし、数を多くすると非常に疲れそうなので退けて(尻込みして)しまいました。(また、長い時間をかけて作っても、1、2回見たらすぐに飽きると思うので、むなしい努力かなぁ、とテンションが下がったのも事実です。)

 

と、いうことで、今回は先般のC#プログラミング学習の復習を兼ねてC#のコンソールプログラムにしてみました。

が、

結構当初の目的は十分に満たしていると思います。存分に改造してもっと面白くしてもらって結構ですので、皆さんも「ハノイの塔プログラミング」をお楽しみください。(注)また、このプログラムのウィンドウ盤は文字列を使わないのでBCCFormに向いています。盤や塔や背景の作成をいとわれない方は、↓を参考にBCCFormで作ってみるのも一興でしょう。

注:エディターとBCCForm and BCCSkeltonパッケージのサンプル、MSCompass.exeがあればWin10、11のPCで遊べます。

 

【C#ハノイの塔<コンソール版>】

//////////////////////////////////////////////////////////////////
// TowerOfHanoi.cs
// Tower of Hanoi, a mathimatic game
// https://www.programmingalgorithms.com/algorithm/tower-of-hanoi/
// 使用上の注意:最大の盤数はPoleクラスで10に設定されています。
//                これを変更する場合には、ShowHanoi()メソッドの60を
//                最大盤数 x 6に、MakeDisk()メソッドの10を最大盤数
//                に変更してください。
//                また、ShowHanoi()メソッドで 0.1秒のウェィトを置い
//                ています(Thread.Sleep(100))が変更可能です。
//////////////////////////////////////////////////////////////////

using System;
using System.Threading;

class TowerOfHanoi
{
    //「TowerOfHanoi」クラス共通変数の宣言
    public static readonly string[] disk = {"|", "□", "□□", "□□□", "□□□□", "□□□□□", "□□□□□□", "□□□□□□□", "□□□□□□□□", "□□□□□□□□□", "□□□□□□□□□□"};
    public static Pole[] pole = new Pole[3];
    public static int tire = 0;

    //Main関数
    public static void Main()
    {
        //段数のユーザー設定
        Console.Write("円盤柱の段数(整数)を入力してください:");
        while(!int.TryParse(Console.ReadLine(), out tire) || tire <= 0)
        {
            Console.Write("\n円盤柱の段数(整数)を入力してください:");
        }
        //3本の柱のインスタンス作成
        for(int i = 0; i < 3; i++)
            pole[i] = new Pole();
        //最初の柱に円盤を設置する
        for(int i = 0; i < tire; i++)
            pole[0].push(tire - i);
        //「ハノイの塔」の初期状態を表示
        ShowHanoi();
        Console.WriteLine("開始します。何かキーを入押してください:");
        Console.ReadKey();
        //「ハノイの塔」の開始
        TowerofHanoi(tire, 0, 1, 2);
        //コンソールを閉じさせない為
        Console.WriteLine("終了しました。何かキーを入押してください:");
        Console.ReadKey();
    }

    public static void TowerofHanoi(int diskCount, int fromPole, int toPole, int viaPole)
    {
        if(diskCount > 0)
        {
            TowerofHanoi(diskCount - 1, fromPole, viaPole, toPole);
            pole[toPole].push(pole[fromPole].pop());
            ShowHanoi();
            Thread.Sleep(100);
            //Console.ReadKey();    //毎回の移動を確認する場合これを使ってください。
            TowerofHanoi(diskCount - 1, viaPole, toPole, fromPole);
        }
    }

    public static void ShowHanoi()
    {
        Console.Clear();
        Console.WriteLine(">>>>> Tower of Hanoi <<<<<\n");
        for(int i = tire - 1; i >= 0; i--)
        {
            Console.WriteLine(MakeDisk(pole[0].getDisk(i)) + MakeDisk(pole[1].getDisk(i)) + MakeDisk(pole[2].getDisk(i)));
        }
        string Horizen = new String('―', 60);
        Console.WriteLine(Horizen);
    }

    public static string MakeDisk(int num)
    {
        return String.Format("{0, 10}", disk[num]) + String.Format("{0, -10}", disk[num]);
    }
}

class Pole
{
    const int MaxTire = 10;
    int[] Disks;
    int Tire = 0;

    public Pole()
    {
        Disks = new int [MaxTire];
    }

    public Pole(int num)
    {
        if(num > MaxTire)
        {
            Disks = new int [MaxTire];
        }
        else
        {
            Disks = new int [num];
        }
    }

    public void push(int num)    //柱に盤を嵌める
    {
        Disks[Tire] = num;
        Tire++;
    }

    public int pop()            //柱から盤を抜き、盤数を返す(なければ0)
    {
        int val = 0;
        if(Tire > 0)
        {
            val = Disks[Tire - 1];
            Disks[Tire - 1] = 0;
            --Tire;
        }
        return val;
    }

    public int getDisk(int num)    //柱のnum番目の盤数を返す(なければ0)
    {
        return Disks[num];
    }
}
 

ps. 先般「ハマった」と書いた"Mirage"ですが、既に飽きました。「ハノイの塔」がそうならないことを祈ります。