본문 바로가기

C#/개발

[C#] 하노이의 탑

계획을 세웠다가 처맞은 프로그램. 원래 계획은 판의 개수를 선택하는 기능을 만들어서 1개~6개중 하나를 선택하게 만들려 했었다(윈폼이 쓸데없이 크고 위에 사용안된 판들이 떠있는 이유). 그 후 기둥마다 스택을 할당해서 push와 pop을 통해 판을 이동시키고 목표 기둥에 모든 판이 들어가면 완료되게 만들려 했다. 그런데 판을 만들기 위해 사용한 RectangleShape가 타입이 없다? 그래서 배열이나 리스트, 스택으로 조작하는게 불가능함...Object로 만들고 Control 써도 안됨. 그럼 케이스를 다 만들어 줘야 하는데, 판 n개를 사용하는 경우 하나당 케이스가 3 x 2 x n 개 나온다. 즉, 케이스만 6 x (1 + 2 + 3 + 4 + 5 + 6) = 216 가지...그리고 판 3개를 구분하는건 리눅스 파일 시스템(숫자 1, 2, 5 조합)을 응용했는데 그 위로는 아는 방법이 없음(스택 썼으면 구분할 필요 X). 그래서 포기하고 판이 3개인 경우만 만들었다.

 

※ 구현 기능

○ 하노이의 탑의 해결과정을 단계별로 확인 가능함

○ 진행 단계 되돌리기 기능

 진행 단계 초기화 기능

 

 

코드

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace Hanoi
{
    public partial class Form1 : Form
    {
        Hanoi hanoi;
        List<Move> movList;
        int phase,flagA,flagB,flagC,AY,BY,CY
            ,AC=105,BC=296,CC=487
            ,floor=315,trayHeight=15,interval=191;
        public Form1()
        {
            List<Object> rect = new List<Object>();
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            init();
        }

        private void btnReset_Click(object sender, EventArgs e)
        {
            init();
        }
        private void btnNext_Click(object sender, EventArgs e)
        {
            move(movList[phase].getBefore, movList[phase].getAfter);
            phase++;
            if (phase == 7)
                btnNext.Enabled = false;
            btnPrev.Enabled = true;
        }
        private void btnPrev_Click(object sender, EventArgs e)
        {
            phase--;
            move(movList[phase].getAfter, movList[phase].getBefore);
            if (phase == 0)
                btnPrev.Enabled = false;
            btnNext.Enabled = true;
        }
        public void init(){
            flagA=8;
            flagB=0;
            flagC=0;
            AY=floor-4*trayHeight;
            BY=floor-trayHeight;
            CY=floor-trayHeight;
            recTray0.Location = new Point(AC - recTray0.Size.Width / 2, AY+trayHeight);
            recTray1.Location = new Point(AC - recTray1.Size.Width / 2, AY+2*trayHeight);
            recTray2.Location = new Point(AC - recTray2.Size.Width / 2, AY+3*trayHeight);
            btnPrev.Enabled = false;
            hanoi = new Hanoi();
            hanoi.show();
            movList = hanoi.getList;
            phase = 0;
            btnPrev.Enabled = false;
            btnNext.Enabled = true;
        }
        public void move(string before, string after)
        {
            switch (before)
            {
                case "A":
                    if (after.Equals("B"))
                    {
                        if (flagA >= 5)
                        {
                            recTray0.Location = new Point(recTray0.Location.X + interval, BY);
                            flagA -= 5;
                            flagB += 5;
                        }
                        else if (flagA == 2||flagA==3)
                        {
                            recTray1.Location = new Point(recTray1.Location.X + interval, BY);
                            flagA -= 2;
                            flagB += 2;
                        }
                        else
                        {
                            recTray2.Location = new Point(recTray2.Location.X + interval, BY);
                            flagA -= 1;
                            flagB += 1;
                        }
                        AY += trayHeight;
                        BY -= trayHeight;
                    }
                    else if (after.Equals("C"))
                    {
                        if (flagA >=5 )
                        {
                            recTray0.Location = new Point(recTray0.Location.X + interval * 2, CY);
                            flagA -= 5;
                            flagC += 5;
                        }
                        else if (flagA == 2 || flagA == 3)
                        {
                            recTray1.Location = new Point(recTray1.Location.X + interval * 2, CY);
                            flagA -= 2;
                            flagB += 2;
                        }
                        else
                        {
                            recTray2.Location = new Point(recTray2.Location.X + interval * 2, CY);
                            flagA -= 1;
                            flagC += 1;
                        }
                        AY += trayHeight;
                        CY -= trayHeight;
                    }break;
                case "B":
                    if (after.Equals("A"))
                    {
                        if (flagB >= 5)
                        {
                            recTray0.Location = new Point(recTray0.Location.X - interval, AY);
                            flagB -= 5;
                            flagA += 5;
                        }
                        else if (flagB == 2 || flagB == 3)
                        {
                            recTray1.Location = new Point(recTray1.Location.X - interval, AY);
                            flagB -= 2;
                            flagA += 2;
                        }
                        else
                        {
                            recTray2.Location = new Point(recTray2.Location.X - interval, AY);
                            flagB -= 1;
                            flagA += 1;
                        }
                        BY += trayHeight;
                        AY -= trayHeight;
                    }
                    else if (after.Equals("C"))
                    {
                        if (flagB >= 5)
                        {
                            recTray0.Location = new Point(recTray0.Location.X + interval , CY);
                            flagB -= 5;
                            flagC += 5;
                        }
                        else if (flagB == 2 || flagB == 3)
                        {
                            recTray1.Location = new Point(recTray1.Location.X + interval , CY);
                            flagB -= 2;
                            flagC += 2;
                        }
                        else
                        {
                            recTray2.Location = new Point(recTray2.Location.X + interval , CY);
                            flagB -= 1;
                            flagC += 1;
                        }
                        BY += trayHeight;
                        CY -= trayHeight;
                    } break;
                case "C":
                    if (after.Equals("A"))
                    {
                        if (flagC >= 5)
                        {
                            recTray0.Location = new Point(recTray0.Location.X - interval*2, AY);
                            flagC -= 5;
                            flagA += 5;
                        }
                        else if (flagC == 2 || flagC == 3)
                        {
                            recTray1.Location = new Point(recTray1.Location.X - interval*2, AY);
                            flagC -= 2;
                            flagA += 2;
                        }
                        else
                        {
                            recTray2.Location = new Point(recTray2.Location.X - interval*2, AY);
                            flagC -= 1;
                            flagA += 1;
                        }
                        CY += trayHeight;
                        AY -= trayHeight;
                    }
                    else if (after.Equals("B"))
                    {
                        if (flagC >= 5)
                        {
                            recTray0.Location = new Point(recTray0.Location.X - interval, BY);
                            flagC -= 5;
                            flagB += 5;
                        }
                        else if (flagC == 2 || flagC == 3)
                        {
                            recTray1.Location = new Point(recTray1.Location.X - interval, BY);
                            flagC -= 2;
                            flagB += 2;
                        }
                        else
                        {
                            recTray2.Location = new Point(recTray2.Location.X - interval, BY);
                            flagC -= 1;
                            flagB += 1;
                        }
                        CY += trayHeight;
                        BY -= trayHeight;
                    } break;
            }
        }
    }
    public class Hanoi
    {
        private int tray = 3;  
        private List<Move> movList=new List<Move>();

        public List<Move> getList { get { return movList; } }

        public Hanoi() { }

        public Hanoi(int tray)
        {
            this.tray = tray;
        }
        public void HanoiTower(int n, String a, String b, String c)
        {
            if (n == 1)
            {
                movList.Add(new Move(a,c));
            }
            else
            {
                this.HanoiTower(n - 1, a, c, b);
                movList.Add(new Move(a, c));
                this.HanoiTower(n - 1, b, a, c);
            }
        }
        public void show()
        {
            HanoiTower(tray, "A", "B", "C");
        }
    }
    public class Move
    {
        private String before, after;
        public string getBefore { get { return before; } }
        public string getAfter { get { return after; } }
        public Move(String before, String after)
        {
            this.before = before;
            this.after = after;
        }
    }
}

'C# > 개발' 카테고리의 다른 글

[C#] 아날로그 시계  (0) 2022.08.05
[C#] 바이오리듬  (0) 2022.08.05
[C#] RSA 암호화 & 복호화  (0) 2022.08.05
[C#] 로또  (0) 2022.08.05
[C#] 웹 이미지 다운로더  (0) 2022.08.05