虽然说昨天应该继续引擎方面的东西,然而我实现逆向A*路径搜索算法的过程中,又遇到了C#的问题,于是又回到了C#语言方面来了....昨天半夜还没写完就睡了...

问题告急:

  1. 如何读取和写入文件
  2. 字符串和数字的相互转换
  3. 实现了一个可以很方便引用的矩阵
  4. 实现了==运算符的重载

下面分别讨论吧(当然我只说了我需求中的一些操作,至于其他操作,各位自寻啦~~~~~):



2.1 字符串转数字


这里为什么不按照顺序写呢,因为文件读写操作里要用到这个,再三考虑,我决定不按常理出牌。


字符串转数字非常简单,看代码:


int x = int.Parse(str);

这里str是string类的。我需要转换为 int 的,所以用的是 int.Parse,其他数值类型使用方法相同。


字符串转数字还有一个方法叫做Convert,自寻~~~



2.2 数字转字符串


数字转换为字符串也是支持格式化和流两种方式,我输出的时候对格式是由需求的,所以用的格式化的方式进行输出


string str = string.Format("{0,5}{1,5}\n", x, y);

解释下{0,5}这个东西,他的形式为


{ 参数的序号 , 参数的长度 : 参数的格式 }


就是说 0 是后面序号为 0  的参数,那么这里就是 x,


逗号后面接字符串的长度,我设置为5



1.1  文件的读取


文件方面的操作,和C++的流很像,名字也一样,也叫作流,但是写起来很方便,这也归功于VS2013比较强大的自动补全。


文件操作需要引用IO类库


using System.IO;


判定文件是否存在:


if( ! System.IO.File.Exists( "filename.txt") ) return false;

然后创建文件流,流读取对象


FileStream file = new FileStream("filename.txt", FileMode.Open, FileAccess.Read);
StreamReader reader;
if (file.CanRead) 
reader = new StreamReader( file ); 
else
{
	file.Close();
	return false;
}




string strLine = reader.ReadLine(); // 读取一行
string[] strs = strLine.Split(' '); // 拆分
int x = int.Parse(strs[0]);
int y = int.Parse(strs[1]);

读取搞定了,别忘了关闭文件和读取流


reader.Close();
file.Close();



1.2 文件的写入

FileStream dataFile = new FileStream(fileName, FileMode.Create, FileAccess.Write);
StreamWriter sw = new StreamWriter(dataFile);

写入数据,并关闭流


string str = “output”;
sw.Write(str);
sw.Close();
dataFile.Close();



3 很方便的矩阵

那其实就是重载了 [] 运算符


public int this[Coord2 coordIn]
{
	get { return data[coordIn.x, coordIn.y]; }
	set { data[coordIn.x, coordIn.y] = value;}
}

对于我的类,重载 [] 运算符,使其接受我自定义的坐标数据,大大简化了我的代码,提高了可读性。


这个定义最关键的是形式

public int this[Coord2 coordIn]

以及 get 、set 、value 三个关键字;


get 表示获取该类数据时所返回的,因而引用自定义类的对象数据时,是这样操作的:


cost[checkNode]

即可获取类中data位置(x,y)的数据


而 set 则是赋值的操作了,value 是赋值时等号右边的值,赋值的操作为:


cost[checkNode] = 10;



4. ==运算符的重载

这个是个纠结的东西,参考


https://msdn.microsoft.com/zh-cn/library/ms173147(VS.80).aspx


就是说 == 、!= 、 Equals(两个,一个重定义,一个正常定义)、GetHashCode 这四个东西是绑定的,动其一则动全部

public static bool operator !=(Coord2 a, Coord2 b)
{
	return !(a == b);
}
public static bool operator ==(Coord2 a, Coord2 b) /// 我其实只想重载这个
{
	if (System.Object.ReferenceEquals(a, b)) return true; /// 这个比较是显式的比较是否为引用相同
	if (null == (object)a || null == (object)b) return false; /// 这里一定要 (object),否则无限迭代
	return (a.x == b.x && a.y == b.y);
}
public bool Equals(Coord2 a)
{
	if (null == a) return false;
	return (a.x == x && a.y == y);
}
public override bool Equals(System.Object obj) /// 对底层的方法进行重新定义
{
	if (null == obj) return false;
	Coord2 inst = obj as Coord2;
	if (null == (System.Object)inst) return false;
	return (inst.x == x && inst.y == y);
}
public override int GetHashCode()/// 方法不唯一
{
	return (x ^ y);
}

多嘴一句,如果这个类不是基类,而是有父类的,那么在返回时还需要考虑 base.Equals,详细见上面的参考链接




最最最后了,学习是要有实践的学习的,所以我也不是光练练代码段的问题,所以呢,我把A*逆向路径搜索算法给实现了,


A*逆向算法功能:


一个2维地图上,1表示障碍物,0表示能通过,从这个地图上的某一个点到另外一个点的最短路径怎么知道呢?A*逆向来帮你。


地图文件说明:


TXT文件,格式为


{


X范围  Y范围


地图数据2维矩阵


}


对X和Y范围做说明:如果X取值是0~5,那么这里是X范围是6,同时地图数据的必须为6列


程序说明:


利用这两天所学知识,把算法实现了,输出了最终的估价矩阵以及最优路径,分别在程序生成的 CostMapOut.txt 和 PathOut.txt 两个文件中;程序的调用方式为(cmd中,切换到程序路径):


PathSearch  mapFileName.txt


没有实现文件搜索,所以程序和文件要在同一路径下。


没有实现起始节点和终止节点的输入,需要在程序里修改 beginNode和EndNode 的值。


没有实现起始节点和终止节点的测试,所以请保证 beginNode 和 EndNode 在地图上的值均为 0。


Node的( x, y) 为坐标值,所以对应到矩阵上为 (列,行),不要混淆,程序里全部都是按照坐标的方式引用的,不是矩阵


坐标的范围均为 0~xMax-1,设置 Node 的坐标时注意


文件包说明:


程序是我在另一台电脑上写的,所以代码是重新敲的,没写注释,需要看注释的看 whole.jpg ,图片里有,map.txt 就是我测试时的地图数据文件。





不过,通过这次经历我明显的感觉到高级语言的优势了,这个程序我用MATLAB做了一次,花了3个小时左右就搞定了,而C#连学带做3个晚上(当然学花了很多时间

),对于这种算法的验证来说,没有什么实时性要求,MATLAB确实很适合



昨天结束,哇咔咔~~~