日期:2014-05-18  浏览次数:20815 次

分享一个C#实现的迷宫生成程序,继续演示LINQ语法在C#中的运用
简单地介绍下这个程序的功能。程序可以自动产生一个迷宫。迷宫的大小可以在
MazeModel mm = new MazeModel(7, 5);
这一行配置。为了简化起见,程序使用控制台输出,稍微修改,可以做到GUI中,效果更好。

迷宫中可以走的路径用|或者-标出,任意两点有且只有一条通路可以到达。大家可以看看自己解迷宫的水平哦。

迷宫算法本质上是一个最小生成树产生算法,这个数据结构大家都学过,忘记的可以自己找出来看看,在本程序中首先建立完整的通路图,然后随机从图中移除一条边,如果移除导致有顶点不可以到达,以后不再尝试移除它,直到图中没有可以移除的边为止。

最后显示输出。

下面是完整的代码,用了一些LINQ来简化搜索边的操作。

C# code
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MazeModel mm = new MazeModel(7, 5);
            mm.DisplayMaze();
        }
    }

    class MazeModel
    {
        private bool[] edges;

        public int HorizontalVertex { get; private set; }

        public int VerticalVertex { get; private set; }

        private bool getEdgeValue(int edgeindex)
        {
            try
            {
                return edges[edgeindex];
            }
            catch
            {
                return false;
            }
        }

        private void setEdgeValue(int edgeindex, bool value)
        {
            try
            {
                edges[edgeindex] = value;
            }
            catch { }
        }

        private int nodeToEdgeIndex(int x, int y, int dir)
        {
            if (x == 0 && dir == 1) return -1;
            if (x % HorizontalVertex == HorizontalVertex - 1 && dir == 2) return -1;
            if (y == 0 && dir == 0) return -1;
            if (y >= HorizontalVertex * (VerticalVertex - 1) && dir == 3) return -1;

            return (y * 2 + ((dir == 1 || dir == 2) ? 0 : (dir == 0 ? -1 : 1))) * HorizontalVertex + x - (dir == 1 ? 1 : 0);
        }

        private int nodeindexToEdgeIndex(int nodeindex, int dir)
        {
            int x;
            int y;
            nodeIndexToNode(nodeindex, out x, out y);
            return nodeToEdgeIndex(x, y, dir);
        }

        private void nodeIndexToNode(int nodeindex, out int x, out int y)
        {
            x = nodeindex % HorizontalVertex;
            y = nodeindex / HorizontalVertex;
        }

        private int nodeToNodeIndex(int x, int y)
        {
            return y * HorizontalVertex + x;
        }

        private void edgeIndexToNodeIndex(int edgeindex, out int node1, out int node2)
        {
            int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
            if (edgeindex / HorizontalVertex % 2 != 0)
            {
                x1 = x2 = edgeindex % HorizontalVertex;
                y1 = edgeindex / (HorizontalVertex * 2);
                y2 = y1 + 1;
            }
            else
            {
                x1 = edgeindex % HorizontalVertex;
                x2 = x1 + 1;
                y1 = y2 = edgeindex / (HorizontalVertex * 2);
            }
            node1 = nodeToNodeIndex(x1, y1);
            node2 = nodeToNodeIndex(x2, y2);
        }

        private int edgeIndexToNodeIndex(int edgeindex, int node)
        {
            int node1, node2;
            edgeIndexToNodeIndex(edgeindex, out node1, out node2);
            return node1 == node ? node2 : node1;
        }

        private IEnumerable<int> getNodeEdges(int nodeIndex, List<int> blocklist)
        {
            return Enumerable
                .Range(0, 4)
                .Select(x => nodeindexToEdgeIndex(nodeIndex, x))
                .Where(x => getEdgeValue(x) && !blocklist.Contains(x));
        }

        private void generateMaze()
        {
            List<int> blockEdges = new List<int>();
            while (blockEdges.Count < HorizontalVertex * VerticalVertex - 1)
            {
                var nodes = Enumerable.Range(0, HorizontalVertex * Vert