分享一个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 * VerticalVertex) .Where(x => getNodeEdges(x, blockEdges).Count() > 1).ToList() .Select(x => new { k = Guid.NewGuid(), v = x }) .OrderBy(x => x.k) .Select(x => x.v).ToList(); if (nodes.Count == 0) return; int node = nodes.First(); var tedges = getNodeEdges(node, blockEdges).ToList() .Select(x => new { k = Guid.NewGuid(), v = x }) .OrderBy(x => x.k) .Select(x => x.v).ToList(); if (tedges.Count == 0) return; int edge = tedges.First(); var edgesbackup = edges.ToArray(); setEdgeValue(edge, false); if (!testMaze()) { blockEdges.Add(edge); edges = edgesbackup; } } } private bool testMaze() { var found = new List<int>() { 0 }; findNode(0, found); return found.Count() == HorizontalVertex * VerticalVertex; } private void findNode(int nodeindex, List<int> found) { var nextNodes = getNodeEdges(nodeindex, new List<int>()) .Select(x => edgeIndexToNodeIndex(x, nodeindex)) .Where(x => !found.Contains(x)) .ToList(); foreach (int item in nextNodes) { found.Add(item); } foreach (int item in nextNodes) { findNode(item, found); } } public MazeModel(int horizontalvertex, int verticalvertex) { HorizontalVertex = horizontalvertex; VerticalVertex = verticalvertex; edges = Enumerable .Range(0, horizontalvertex * (verticalvertex * 2 - 1) - 1) .Select(x => x % horizontalvertex != horizontalvertex - 1 || x / horizontalvertex % 2 != 0 ).ToArray(); generateMaze(); } public void DisplayMaze() { for (int i = 0; i < VerticalVertex; i++) { for (int j = 0; j < HorizontalVertex; j++) { Console.Write("X"); if (j != HorizontalVertex - 1) { Console.Write(getEdgeValue(nodeToEdgeIndex(j, i, 2)) ? "-" : " "); } } Console.WriteLine(); for (int j = 0; j < HorizontalVertex; j++) { if (i != VerticalVertex - 1) { Console.Write(getEdgeValue(nodeToEdgeIndex(j, i, 3)) ? "|" : " "); Console.Write(" "); } } Console.WriteLine(); } } }}
[解决办法]
最近论坛经常有讨论LINQ的帖子啊。。。
[解决办法]
几年前微软有一个很小的程序demo:LINQRayTracer,有兴趣的人可以下载来运行一下。
[解决办法]
用100行代码写出来5000行甚至上万行代码也难以写明白的逻辑程序,以一种纯粹说明性(而非过程性)的方式高效率地进行应用系统开发,很多貌似非常复杂的逻辑可能只需要一条linq代码就可以了,除了Linq还能有什么呢?
例如我们有一个复杂的算法题目,例如针对用户收到的一批订单逐一找出每一个订单条款适合的政策规定(几千条政策规定预先录入好了),然后自动修订其中的各个条款使得凡是不合规矩的条款都可以参照政策规定进行向上或者向下的调整,最终重新输出所有整理过后的订单。这整个工程,可以用一条linq语句搞定。而其它的代码,不过是进行一些与算法无关的操作。
[解决办法]
支持。。。。
最近曹哥都分享Linq的应用。。。
看样子这是几个Linq水帖之后的产物。。。
[解决办法]
LINQ确实简化了很多数据操作,操作起来也比较容易。
[解决办法]
支持 还需努力
[解决办法]
LING 顶上
[解决办法]
曹哥爱linq
sp哥爱SL
[解决办法]
[解决办法]
表示弄过一条300行左右的存储过程
[解决办法]
C#没学过,一直Java不知道该不该学学C#
[解决办法]
除了调试,linq确实招人疼,呵呵
[解决办法]
8错8错
[解决办法]
跑起来 有点慢
[解决办法]
Linq太TM恶心了,效率太慢。
我用Lonq to SQL 参与开发过一个项目,还用的MVC3.0的框架。
项目做好后,我才知道原来所谓的Linq就这么恶心,说句实话都不如三层跑的快!
就这个网站,好长时间没登了,不知道怎么样了(我辞职了)。
[解决办法]
LINQ 不支持 ORACLE,肿么办呢?
[解决办法]
[解决办法]
LZ好象是用lambda表达式搞的,这个标准的linq语法还是有区别。
简单的可能用lambda,复杂的,用from x in y select 这样的还是清晰一点吧?
[解决办法]
LINQ应该是一种提高开发效率但是降低了运行效率的东西。。而且不宜调试,不能过于追捧。只能写些小程序,比如学校老师布置给学生的小作业。。
[解决办法]
[解决办法]
一直都知道LINQ的强大,但实际中实在用的太少了,看来我们都必须花点心思来琢磨琢磨它。