4. 動態路線規劃系統

BFS

namespace Q4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Close();
        }

        enum State
        {
            S, E, O
        }

        State?[,] gay = new State?[11, 11];

        private void panel2_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.FillEllipse(Brushes.Black, 2, 0, 30, 30);
            e.Graphics.DrawString("路障點 O", new Font(FontFamily.GenericSansSerif, 14), Brushes.Black, 35, 5);

            e.Graphics.DrawEllipse(new Pen(Brushes.Blue, 2), 2, 40, 30, 30);
            e.Graphics.DrawString("起點 S", new Font(FontFamily.GenericSansSerif, 14), Brushes.Black, 35, 45);

            e.Graphics.DrawRectangle(new Pen(Brushes.Red, 2), 2, 80, 30, 30);
            e.Graphics.DrawString("終點 T", new Font(FontFamily.GenericSansSerif, 14), Brushes.Black, 35, 85);
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            for (int i = 0; i < 11; i++)
            {
                e.Graphics.DrawLine(new Pen(Brushes.Black, 2), i * 44 + 15, 15, i * 44 + 15, 440 + 15);
                e.Graphics.DrawLine(new Pen(Brushes.Black, 2), 15, i * 44 + 15, 440 + 15, i * 44 + 15);
            }

            if (finalPath != null)
            {
                var last = finalPath[0];
                foreach (var item in finalPath[1..])
                {
                    e.Graphics.DrawLine(new Pen(Brushes.Blue, 3), last.X * 44 + 15, last.Y * 44 + 15, item.X * 44 + 15, item.Y * 44 + 15);
                    last = item;
                }
            }

            for (int x = 0; x < 11; x++)
                for (int y = 0; y < 11; y++)
                {
                    switch (gay[x, y])
                    {
                        case State.O:
                            e.Graphics.FillEllipse(Brushes.Black, x * 44, y * 44, 30, 30);
                            break;
                        case State.S:
                            e.Graphics.FillEllipse(Brushes.White, x * 44, y * 44, 30, 30);
                            e.Graphics.DrawEllipse(new Pen(Brushes.Blue, 2), x * 44, y * 44, 30, 30);
                            break;
                        case State.E:
                            e.Graphics.FillRectangle(Brushes.White, x * 44, y * 44, 30, 30);
                            e.Graphics.DrawRectangle(new Pen(Brushes.Red, 2), x * 44, y * 44, 30, 30);
                            break;
                    }
                }
        }

        List<Point>? finalPath = null;

        private void button1_Click(object sender, EventArgs e)
        {
            gay = new State?[11, 11];

            for (int i = 0; i < 32; i++) genPoint(State.O);
            genPoint(State.S);
            genPoint(State.E);

            findPath();
            panel1.Refresh();
        }


        void findPath()
        {
            system.Text = "規劃路線失敗";

            finalPath = null;

            Point? start = null;
            Point? end = null;

            for (int x = 0; x < 11; x++)
                for (int y = 0; y < 11; y++)
                {
                    if (gay[x, y] == State.S) start = new Point(x, y);
                    if (gay[x, y] == State.E) end = new Point(x, y);
                }

            if (start == null || end == null) return;

            HashSet<Point> visited = new();
            Queue<(Point, List<Point>)> task = new Queue<(Point, List<Point>)>();
            task.Enqueue((start.Value, new()));
            while (task.Count != 0)
            {
                var (curr, path) = task.Dequeue();
                if (visited.Contains(curr) ||
                    curr.X >= 11 || curr.Y >= 11 ||
                    curr.X <0 || curr.Y < 0 ||
                    gay[curr.X, curr.Y] == State.O)
                {
                    continue;
                }
                visited.Add(curr);
                path.Add(curr);

                if (gay[curr.X, curr.Y] == State.E)
                {
                    finalPath = path;
                    system.Text = "規劃路線成功";
                    return;
                }

                task.Enqueue((new Point(curr.X + 1, curr.Y), [.. path]));
                task.Enqueue((new Point(curr.X - 1, curr.Y), [.. path]));
                task.Enqueue((new Point(curr.X, curr.Y + 1), [.. path]));
                task.Enqueue((new Point(curr.X, curr.Y - 1), [.. path]));
            }
        }

        void genPoint(State s)
        {
            var rd = new Random();
            int x, y;
            do
            {
                x = rd.Next(11);
                y = rd.Next(11);
            } while (gay[x, y] != null);
            gay[x, y] = s;
        }

        State? last;
        private void panel1_MouseClick(object sender, MouseEventArgs e)
        {
            var x = (int)Math.Round((e.X - 15) / 44.0);
            var y = (int)Math.Round((e.Y - 15) / 44.0);
            if (x < 0 || y < 0 || x > 10 | y > 10) return;

            if (last == null && gay[x, y] != null)
            {
                system.Text = "";
                last = gay[x, y];
                gay[x, y] = null;
                finalPath = null;
                panel1.Refresh();
            } else
            if (last != null && gay[x, y] == null)
            {
                gay[x, y] = last;
                last = null;
                findPath();
                panel1.Refresh();
            }
        }
    }
}

Last updated