科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件使用 C# 开发智能手机软件:推箱子(十)

使用 C# 开发智能手机软件:推箱子(十)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在上篇文章“使用 C# 开发智能手机软件:推箱子(九)”中,我对Common/ConfigFile.cs 源程序文件进行了介绍。

作者:银河 来源:博客园 2007年11月17日

关键字: C# 智能手机 软件 推箱子

  • 评论
  • 分享微博
  • 分享邮件
在上篇文章使用 C# 开发智能手机软件推箱子(九)”中,我对Common/ConfigFile.cs 源程序文件进行了介绍。在这篇文章中,介绍 Common/DataFile.cs 源程序文件。这个源程序文件中包含密封类 DataFile,用来管理数据文件。

使用 C# 开发智能手机软件:推箱子

  上图是数据文件 konka.bxb 的结构图。该数据文件大小为 297 字节,包含三个关卡,各个关卡的大小分别为:“8x7”、“8x7”和“9x5”。内容如下:

  1. 文件头(32字节,图中的青色部分)。首先是保留的四个字节。然后是一个字节的数据文件版本号(目前为“2”)。接着是三个字节的标志(内容为“BOX”)。接着是十六字节的组名(编码为“GB2312”,本数据文件中为“康佳”)。接着是总关数(Int32,四个字节,因为本组共有三个关卡,所以内容为“3”)。最后是第一关起始地址位置(Int32,四个字节,本数据文件中的内容为“0x11D”)。

  2. 以关数据头(32字节,图中的绿色部分)开始的各关数据。首先是一个字节的关数据头开始标志(“@”)。然后是一个字节的标志(最低位:0:未通关,1:已通关)。接着是通关总步数(Int32,四个字节)。接着是通关推箱子步数(Int32,四个字节)。接着是十四个字节的保留字段。接着是本关的宽度(Int32,四个字节)。接着是本关的高度(Int32,四个字节)。最后是“本关宽度x本关高度”个字节的关数据,也就是说地图中每个单元格占一个字节,取值范围是“0”到“7”,分别表示:0:地,1:槽,2:墙,3:砖,4:箱子放在地上,5:箱子放在槽上,6:工人站在地上,7:工人站在槽上。注意,每一个关卡必须刚好有一个工人。

  3. 数据文件的最后是各关起始地址列表(“总关数x4”个字节,图中的黄色部分)。每关的起始地址均为四个字节(Int32),所以共有“总关数x4”个字节。

  密封类 DataFile 的源代码中有详细的注释,很容易看懂。

  1. InitMap 方法用来初始化地图。地图的大小是“(关的高度+2) x (关的宽度+2)”,这是为了在地图四周砌上围墙,以免搜索算法越出地图边界。

  2. DeleteLevel 方法用来删除指定的关。注意,删除关时并不删除关数据,只是将该关的起始地址从各关地址列表中删除,然后将文件缩短四个字节(因为各关地址列表在数据文件的最后)。这样数据文件中就可能包含不需要的冗余数据。通过“菜单 -> 数据 -> 转换”,先“导出”,然后“导入”,可以消除冗余数据。

以下是引用片段:
  1 using System;
  2 using System.IO;
  3 using System.Drawing;
  4 using System.Collections.Generic;
  5 using System.Windows.Forms;
  6
  7 namespace Skyiv.Ben.PushBox.Common
  8 {
  9 // data/.bxb 文件格式
  10 // 保留 ver(2) BOX 组名- 总关数 第1关起始地址位置
  11 // 0--3 4----- 5-7 8--23 24--27 28-------------31
  12 //
  13 // @ Flag 总步数 推箱子步数 保留- wide- high- data
  14 // 0 1--- 2----5 6--------9 10-23 24-27 28-31 32..
  15 // Flag: 最低位: 0:未通关 1:已通关
  16 //
  17 // 第1关起始地址 第2关起始地址 . 最后一关起始地址
  18 // 0-----------3 4-----------7 . (文件最后四字节)
  19 //
  20 // steps/.bxs 文件格式见 Step.cs
  21 // 其中为关数(1起始),最少四位,不足前补零
  22 //
  23 // text/.bxa 文件格式
  24 // 0 - land SPACE
  25 // 1 + slot .
  26 // 2 # wall #
  27 // 3 % brick N/A
  28 // 4 x box on land $
  29 // 5 X box on slot *
  30 // 6 ( man on land @
  31 // 7 ) man on slot + .XSB 文件格式
  32 // 第一行如果以!开头的话, 则为组名(不能超过16个字符)
  33 // 以:开头的行为通关步骤, 格式同(.bxs)文件
  34 // 以'开头的行为注释, 完全忽略
  35 // 各关之间必须以空行分隔
  36
  37 /// 
  38 /// 管理数据文件: *.bxb *.bxa *.bxs
  39 /// 
  40 sealed class DataFile : IDisposable
  41 {
  42 const byte DataVersion = 2; // 数据文件(.bxb)的版本
  43 const byte LevelFlag = (byte)'@'; // 数据文件(.bxb)的关标志
  44 const char RemChar = '\''; // 文本文件(.bxa)的注释
  45 const char StepsChar = ':'; // 文本文件(.bxa)的通关步骤
  46
  47 FileStream fs; // 数据文件基础
  48 BinaryReader br; // 数据文件读取器
  49 BinaryWriter bw; // 数据文件写入器
  50 string groupName; // 当前组名称
  51 int[] addrs; // 各关起始地址列表,最后一项为第1关起始地址位置
  52 byte[,] map; // 当前关地图
  53 int maxLevel; // 总关数
  54 Size levelSize; // 当前关尺寸(以单元格为单位)
  55 Point worker; // 当前工人位置(以单元格为单位)
  56 int mans; // 工人数
  57 int boxs; // 箱子数
  58 int slots; // 槽数
  59 int tasks; // 总任务数
  60 int boths; // 已完成任务数
  61 bool isFinished; // 是否曾经通关
  62 int movedSteps; // 通关的总步数
  63 int pushedSteps; // 通关的推箱子步数
  64 string fileName { get { return Path.GetFileNameWithoutExtension(fs.Name); } } // 数据文件主名
  65
  66 public string GroupName { get { return groupName; } }
  67 public int MaxLevel { get { return maxLevel; } }
  68 public byte[,] Map { get { return map; } }
  69 public Size LevelSize { get { return levelSize; } }
  70 public bool IsFinished { get { return isFinished; } }
  71 public int MovedSteps { get { return movedSteps; } }
  72 public int PushedSteps { get { return pushedSteps; } }
  73 public Point Worker { get { return worker; } }
  74 public bool HasWorker { get { return mans != 0; } }
  75 public int Boxs { get { return boxs; } }
  76 public int Slots { get { return slots; } }
  77 public int Tasks { get { return tasks; } }
  78 public int Boths { get { return boths; } set { boths = value; } }
  79
  80 /// 
  81 /// 装入组数据
  82 /// 
  83 /// 组文件名
  84 public void LoadGroup(string name)
  85 {
  86 Dispose();
  87 fs = new FileStream(Path.Combine(Pub.DataDirectory, name + Pub.DataExtName), FileMode.Open);
  88 br = new BinaryReader(fs, Pub.Encode);
  89 bw = new BinaryWriter(fs, Pub.Encode);
  90 br.ReadInt32(); // 保留
  91 if (br.ReadByte() != DataVersion) throw new Exception("数据文件版本错");
  92 byte[] bs = br.ReadBytes(3); // 数据文件标志:BOX
  93 for (int i = 0; i < bs.Length; i++) if (bs[i] != "BOX"[i]) throw new Exception("数据文件标志错");
  94 bs = br.ReadBytes(16); // 组名
  95 for (int i = 0; i < bs.Length; i++) if (bs[i] == 0) bs[i] = 32;
  96 groupName = Pub.Encode.GetString(bs, 0, bs.Length).Trim();
  97 if (groupName.Length == 0) groupName = fileName; // 如果数据文件中组名为空,则用数据文件主名代替
  98 maxLevel = br.ReadInt32(); // 总关数
  99 int addrPos = br.ReadInt32(); // 第1关起始地址位置
  100 br.BaseStream.Seek(addrPos, SeekOrigin.Begin);
  101 addrs = new int[maxLevel + 1]; // 各关起始地址列表,最后一项为第1关起始地址位置
  102 for (int i = 0; i < maxLevel; i++) addrs[i] = br.ReadInt32();
  103 addrs[maxLevel] = addrPos; // 第1关起始地址位置
  104 if (addrPos + 4 * maxLevel != br.BaseStream.Length) throw new Exception("数据文件地址表必须位于数据最后");
  105 }
  106
  107 /// 
  108 /// 装入关数据
  109 /// 
  110 /// 关数
  111 public void LoadLevel(int level)
  112 {
  113 LoadLevelHead(level);
  114 InitMap();
  115 for (int i = 1; i <= levelSize.Height; i++)
  116 {
  117 for (int j = 1; j <= levelSize.Width; j++)
  118 {
  119 map[i, j] = br.ReadByte();
  120 UpdateCounts(j, i, true);
  121 }
  122 }
  123 if (mans != 1) throw new Exception("读取关数据失败:必须刚好有一个工人");
  124 tasks = Math.Min(boxs, slots);
  125 }
  126
  127 /// 
  128 /// 新建一关
  129 /// 
  130 /// 是否复制当前关
  131 /// 新建关的尺寸
  132 public void NewLevel(bool isCopy, Size size)
  133 {
  134 Size levelSizeOem = levelSize;
  135 byte[,] mapOem = isCopy ? (byte[,])map.Clone() : null;
  136 levelSize = size;
  137 InitMap();
  138 for (int i = 1; i <= levelSize.Height; i++)
  139 {
  140 for (int j = 1; j <= levelSize.Width; j++)
  141 {
  142 map[i, j] = (isCopy && i <= levelSizeOem.Height && j <= levelSizeOem.Width) ? mapOem[i, j] : Block.Land;
  143 UpdateCounts(j, i, true);
  144 }
  145 }
  146 if (mans != 1 && mans != 0) throw new Exception("不能超过一个工人");
  147 tasks = Math.Min(boxs, slots);
  148 }
  149
  150 /// 
  151 /// 初始化地图
  152 /// 
  153 private void InitMap()
  154 {
  155 map = new byte[levelSize.Height + 2, levelSize.Width + 2];
  156 for (int i = 0; i <= levelSize.Height + 1; i++) map[i, 0] = map[i, levelSize.Width + 1] = Block.Wall;
  157 for (int j = 0; j <= levelSize.Width + 1; j++) map[0, j] = map[levelSize.Height + 1, j] = Block.Wall;
  158 mans = boxs = slots = boths = 0;
  159 }
  160
  161 /// 
  162 /// 根据地图项目更新统计信息
  163 /// 
  164 /// 当前位置横坐标
  165 /// 当前位置纵坐标
  166 /// 加或减
  167 public void UpdateCounts(int x, int y, bool isAdd)
  168 {
  169 int sign = isAdd ? 1 : -1;
  170 if (Block.IsBox(map[y, x])) boxs += sign;
  171 if (Block.IsSlot(map[y, x])) slots += sign;
  172 if (Block.Box1 == map[y, x]) boths += sign;
  173 if (Block.IsMan(map[y, x]))
  174 {
  175 mans += sign;
  176 worker = isAdd ? new Point(x, y) : Point.Empty;
  177 }
  178 }
  179
  180 /// 
  181 /// 装入关数据头
  182 /// 
  183 /// 关数
  184 void LoadLevelHead(int level)
  185 {
  186 if (level > maxLevel - 1) throw new Exception(string.Format("当前关数({0})不能大于总关数({1})", level + 1, maxLevel));
  187 br.BaseStream.Seek(addrs[level], SeekOrigin.Begin);
  188 if (br.ReadByte() != LevelFlag) throw new Exception("关数据标志错");
  189 isFinished = (br.ReadByte() & 1) == 1; // 是否曾经通关
  190 movedSteps = br.ReadInt32(); // 通关的总步数
  191 pushedSteps = br.ReadInt32(); // 通关的推箱子步数
  192 br.ReadBytes(14); // 保留
  193 levelSize.Width = br.ReadInt32();
  194 levelSize.Height = br.ReadInt32();
  195 }
  196
  197 /// 
  198 /// 更新当前关数据
  199 /// 
  200 /// 关数
  201 /// 通关步骤
  202 /// 推箱子步数
  203 public void SaveLevel(int level, Step[] steps, int pushs)
  204 {
  205 SaveLevelHead(level, steps.Length, pushs);
  206 SaveLevelSteps(level, Pub.ToString(steps));
  207 LoadLevelHead(level);
  208 }
  209
  210 /// 
  211 /// 更新当前关头数据
  212 /// 
  213 /// 关数
  214 /// 通关步数
  215 /// 推箱子步数
  216 void SaveLevelHead(int level, int moves, int pushs)
  217 {
  218 if (level > maxLevel - 1) throw new Exception("关数太大");
  219 bw.BaseStream.Seek(addrs[level] + 1, SeekOrigin.Begin);
  220 bw.Write((byte)1); // 是否曾经通关
  221 bw.Write(moves); // 通关的总步数
  222 bw.Write(pushs); // 通关的推箱子步数
  223 }
  224
  225 /// 
  226 /// 保存通关步骤
  227 /// 
  228 /// 关数
  229 /// 通关步骤
  230 void SaveLevelSteps(int level, string steps)
  231 {
  232 if (!Directory.Exists(Pub.StepsDirectory)) Directory.CreateDirectory(Pub.StepsDirectory);
  233 Fcl.WriteAllText(GetStepsFileName(fileName, level), steps);
  234 }
  235
  236 /// 
  237 /// 给出通关步骤
  238 /// 
  239 /// 关数
  240 /// 通关步骤
  241 public string GetSteps(int level)
  242 {
  243 return GetSteps(fileName, level);
  244 }
  245
  246 string GetSteps(string name, int level)
  247 {
  248 return Fcl.ReadAllText(GetStepsFileName(name, level));
  249 }
  250
  251 string GetStepsFileName(string name, int level)
  252 {
  253 return Path.Combine(Pub.StepsDirectory, name + (level + 1).ToString("D4") + Pub.StepsExtName);
  254 }
  255
  256 /// 
  257 /// 删除通关步骤文件
  258 /// 
  259 /// 关数
  260 private void DeleteStepsFile(int level)
  261 {
  262 // 虽然 File.Delete(): 删除指定的文件。如果指定的文件不存在,则不引发异常。
  263 // 但是: 如果指定的路径无效,还是会引发 DirectoryNotFoundException 异常。
  264 // 所以需要先用 File.Exists() 判断一下文件是否存在
  265 string name = GetStepsFileName(fileName, level);
  266 if (File.Exists(name)) File.Delete(name);
  267 }
  268
  269 /// 
  270 /// 保存设计数据
  271 /// 
  272 /// 是否新建
  273 /// 要保存的关数
  274 public void SaveDesign(bool isNew, int level)
  275 {
  276 if (isNew && level != maxLevel) throw new Exception("新建的关必须在最后一关之后");
  277 bw.BaseStream.Seek(addrs[level], SeekOrigin.Begin);
  278 WriteLevel(level, string.Empty); // 如果不是新建,则关尺寸不能比原来的大
  279 if (isNew)
  280 {
  281 Fcl.Resize(ref addrs, addrs.Length + 1);
  282 addrs[++maxLevel] = (int)bw.BaseStream.Position;
  283 WriteAddrs();
  284 }
  285 DeleteStepsFile(level); // 删除通关步骤文件
  286 }
  287
  288 /// 
  289 /// 删除最后一关
  290 /// 
  291 /// 关数(必须是最后一关)
  292 public void DeleteLastLevel(int level)
  293 {
  294 if (level != maxLevel - 1) throw new Exception("要删除的关必须是最后一关");
  295 DeleteLevel(level);
  296 DeleteStepsFile(level); // 删除通关步骤文件,如果被删除的关不是最后一关,以后各关的通关步骤文件就不对了
  297 }
  298
  299 /// 
  300 /// 删除指定的关
  301 /// 
  302 /// 关数
  303 void DeleteLevel(int level)
  304 {
  305 for (int i = level + 1; i <= maxLevel; i++) addrs[i - 1] = addrs[i]; // 之后的关起始地址前移
  306 --maxLevel; // 更新总关数
  307 WriteAddrs();
  308 }
  309
  310 /// 
  311 /// 更新各关起始地址列表及总关数和第1关起始地址位置
  312 /// 
  313 private void WriteAddrs()
  314 {
  315 bw.Seek(addrs[maxLevel], SeekOrigin.Begin);
  316 for (int i = 0; i < maxLevel; i++) bw.Write(addrs[i]); // 各关起始地址
  317 bw.BaseStream.SetLength(bw.BaseStream.Position); // 关起始地址列表位于数据文件最后, 用于删除关的情况
  318 bw.Seek(24, SeekOrigin.Begin);
  319 bw.Write(maxLevel); // 总关数
  320 bw.Write(addrs[maxLevel]); // 第1关起始地址位置
  321 }
  322
  323 /// 
  324 /// 更新组名
  325 /// 
  326 void WriteGroupName()
  327 {
  328 byte[] bs = new byte[16];
  329 byte[] bn = Pub.Encode.GetBytes(groupName);
  330 for (int i = 0; i < bs.Length && i < bn.Length; i++) bs[i] = bn[i];
  331 for (int i = bn.Length; i < bs.Length; i++) bs[i] = 32;
  332 bw.Seek(8, SeekOrigin.Begin);
  333 bw.Write(bs); // 组名
  334 }
  335
  336 /// 
  337 /// 写关数据和通关步骤
  338 /// 注意:调用本函数前必须定位到数据文件的正确位置
  339 /// 
  340 /// 关数
  341 /// 通关步骤
  342 /// 本关的统计信息
  343 string WriteLevel(int level, string steps)
  344 {
  345 bw.Write(LevelFlag); // 关标志
  346 bw.Write((byte)(string.IsNullOrEmpty(steps) ? 0 : 1)); // 标志:是否已通关
  347 bw.Write(steps.Length); // 总步数
  348 bw.Write(GetPushSteps(steps)); // 推箱子步数
  349 bw.Write(new byte[14]); // 保留
  350 bw.Write(levelSize.Width); // 当前关宽度
  351 bw.Write(levelSize.Height); // 当前关高度
  352 mans = slots = boxs = 0;
  353 int lands = 0, walls = 0, bricks = 0;
  354 for (int i = 1; i <= levelSize.Height; i++)
  355 {
  356 for (int j = 1; j <= levelSize.Width; j++)
  357 {
  358 bw.Write(map[i, j]);
  359 switch (map[i, j])
  360 {
  361 case Block.Land: lands++; break;
  362 case Block.Slot: slots++; break;
  363 case Block.Wall: walls++; break;
  364 case Block.Brick: bricks++; break;
  365 case Block.Box0: lands++; boxs++; break;
  366 case Block.Box1: slots++; boxs++; break;
  367 case Block.Man0: lands++; mans++; break;
  368 case Block.Man1: slots++; mans++; break;
  369 }
  370 }
  371 }
  372 if (mans != 1) ErrorExit(true, level + 1, "必须刚好有一个工人");
  373 if (!string.IsNullOrEmpty(steps)) SaveLevelSteps(level, steps);
  374 return string.Format("{1}: {2} {3} {4} {5} {6} {7} {8}{0}",
  375 Fcl.NewLine, level + 1, Pub.ToString(levelSize), walls, bricks, lands, slots, boxs, steps.Length);
  376 }
  377
  378 /// 
  379 /// 根据通关步骤给出推箱子步数
  380 /// 
  381 /// 通关步骤
  382 /// 推箱子步数
  383 int GetPushSteps(string steps)
  384 {
  385 int n = 0;
  386 foreach (char c in steps) if (((Step)c).IsBox) n++;
  387 return n;
  388 }
  389
  390 /// 
  391 /// 数据导入
  392 /// 
  393 /// 数据文件主名
  394 /// 最大关尺寸
  395 /// 显示相关信息的文本框
  396 public void Import(string name, int maxLevelSize, TextBox tbxMsg)
  397 {
  398 try
  399 {
  400 tbxMsg.Text = string.Format("{1} => {2}{0}", Fcl.NewLine, name + Pub.TextExtName, name + Pub.DataExtName);
  401 if (!Directory.Exists(Pub.DataDirectory)) Directory.CreateDirectory(Pub.DataDirectory);
  402 using (StreamReader sr = new StreamReader(Path.Combine(Pub.TextDirectory, name + Pub.TextExtName), Pub.Encode))
  403 {
  404 Dispose();
  405 fs = new FileStream(Path.Combine(Pub.DataDirectory, name + Pub.DataExtName), FileMode.Create, FileAccess.Write);
  406 bw = new BinaryWriter(fs, Pub.Encode);
  407 byte[] buf = new byte[32];
  408 buf[4] = DataVersion;
  409 buf[5] = (byte)'B';
  410 buf[6] = (byte)'O';
  411 buf[7] = (byte)'X';
  412 bw.Write(buf);
  413 map = new byte[maxLevelSize + 2, maxLevelSize + 2];
  414 List addrList = new List(); // 各关起始地址列表,最后一项为第1关起始地址位置
  415 addrList.Add((int)bw.BaseStream.Position); // 第1关起始地址
  416 groupName = name; // 组名
  417 int level = 0;
  418 levelSize = Size.Empty;
  419 string steps = ""; // 通关步骤
  420 bool isFirst = true;
  421 for (int line = 1; ; line++)
  422 {
  423 string s = sr.ReadLine();
  424 if (s != null) s = s.Trim();
  425 if (line == 1 && s != null && s.Length > 0 && s[0] == '!')
  426 {
  427 groupName = s.Substring(1).Trim();
  428 tbxMsg.Text += "组名: [" + groupName + "]" + Fcl.NewLine;
  429 continue;
  430 }
  431 if (isFirst)
  432 {
  433 isFirst = false;
  434 tbxMsg.Text += "#: 宽x高 墙 砖 地 槽 箱 通关步数" + Fcl.NewLine;
  435 }
  436 if ((s == null || s.Length == 0) && levelSize != Size.Empty)
  437 {
  438 tbxMsg.Text += WriteLevel(level, steps);
  439 addrList.Add((int)bw.BaseStream.Position); // 下一关起始地址
  440 level++;
  441 levelSize = Size.Empty;
  442 steps = "";
  443 }
  444 if (s == null) break;
  445 if (s.Length == 0 || s[0] == RemChar) continue;
  446 if (s[0] == StepsChar)
  447 {
  448 steps = s.Substring(1).Trim(); // 通关步骤
  449 continue;
  450 }
  451 levelSize.Height++;
  452 if (levelSize.Height == 1) levelSize.Width = s.Length;
  453 else if (levelSize.Width != s.Length) ErrorExit(false, line, "宽度不齐");
  454 if (levelSize.Width > maxLevelSize) ErrorExit(false, line, GetMessage("宽度太大", true));
  455 if (levelSize.Height > maxLevelSize) ErrorExit(false, line, GetMessage("高度太大", true));
  456 for (int i = 0; i < levelSize.Width; i++)
  457 if (!Block.IsBlock(map[levelSize.Height, i + 1] = Block.GetByte(s[i])))
  458 ErrorExit(false, line, "非法字符:[" + s[i] + "]");
  459 }
  460 addrs = addrList.ToArray();
  461 maxLevel = level;
  462 WriteAddrs();
  463 WriteGroupName();
  464 }
  465 }
  466 catch (OutOfMemoryException ex)
  467 {
  468 throw new Exception(GetMessage("内存不足", false), ex);
  469 }
  470 finally
  471 {
  472 Dispose();
  473 }
  474 tbxMsg.Text += "导入完成";
  475 }
  476
  477 string GetMessage(string msg1, bool isIncrease)
  478 {
  479 return msg1 + ",请在“菜单 -> 选项”对话框中" + (isIncrease ? "增加" : "减少") +"“最大关尺寸”";
  480 }
  481
  482 /// 
  483 /// 数据导出
  484 /// 
  485 /// 数据文件主名
  486 /// 显示相关信息的文本框
  487 public void Export(string name, TextBox tbxMsg)
  488 {
  489 try
  490 {
  491 tbxMsg.Text = string.Format("{1} => {2}{0}", Fcl.NewLine, name + Pub.DataExtName, name + Pub.TextExtName);
  492 LoadGroup(name);
  493 if (!Directory.Exists(Pub.TextDirectory)) Directory.CreateDirectory(Pub.TextDirectory);
  494 using (StreamWriter sw = new StreamWriter(
  495 Path.Combine(Pub.TextDirectory, name + Pub.TextExtName), false, Pub.Encode))
  496 {
  497 sw.WriteLine("! {0}", groupName);
  498 tbxMsg.Text += "组名: [" + groupName + "]" + Fcl.NewLine;
  499 tbxMsg.Text += "#: 宽x高 总任务数 通关步数" + Fcl.NewLine;
  500 for (int level = 0; level < maxLevel; level++)
  501 {
  502 LoadLevel(level);
  503 sw.WriteLine("{0}[{1}]", RemChar, level + 1); // 注释:第几关
  504 for (int y = 0; y < levelSize.Height; y++)
  505 {
  506 for (int x = 0; x < levelSize.Width; x++) sw.Write(Block.GetChar(map[y + 1, x + 1]));
  507 sw.WriteLine();
  508 }
  509 string steps = GetSteps(name, level); // 通关步骤
  510 if (!string.IsNullOrEmpty(steps)) sw.WriteLine(StepsChar + steps);
  511 sw.WriteLine();
  512 tbxMsg.Text += string.Format("{1}: {2} {3} {4}{0}",
  513 Fcl.NewLine, level + 1, Pub.ToString(levelSize), tasks, steps.Length);
  514 }
  515 }
  516 }
  517 finally
  518 {
  519 Dispose();
  520 }
  521 tbxMsg.Text += "导出完成";
  522 }
  523
  524 void ErrorExit(bool isLevel, int idx, string msg)
  525 {
  526 throw new Exception(string.Format("错误:第{0}{1}:{2}", idx, isLevel ? "关" : "行", msg));
  527 }
  528
  529 public void Dispose()
  530 {
  531 if (br != null) br.Close();
  532 if (bw != null) bw.Close();
  533 if (fs != null) fs.Close();
  534 br = null;
  535 bw = null;
  536 fs = null;
  537 }
  538 }
  539 }
  540

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章