はてなキーワード: FileStreamとは
これで40分。
タイムアタックってことでアルゴリズムは全幅探索で書き上げました。
エラーチェック皆無。
A*ならもう5分ほど延びるかな?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Maze { class Program { // 探索用地図 static int[,] maze; // 始点終点 static Position Start = new Position(0, 0), Goal = new Position(0, 0); static void Main(string[] args) { //////////////////////////// まずは各行のリストとして読み込み string[] inMaze; using (var fp = new FileStream(args[0], FileMode.Open, FileAccess.Read)) using (var iStream = new StreamReader(fp)) inMaze = iStream.ReadToEnd().Split('\n'); // 迷路幅 int height = inMaze.Length; // 迷路高さ int width = inMaze[0].Length; /////////////////////////// 読み込んだ迷路を作業用地図に展開 maze = new int[width, height]; for (int y = 0; y < height; ++y) { string line = inMaze[y]; for (int x = 0; x < line.Length; ++x) { maze[x, y] = line[x] == '*' ? -1 : 0; if (line[x] == 'S') Start = new Position(x, y); if (line[x] == 'G') Goal = new Position(x, y); } } // 探索実行 int dist = Search(maze, Start); // 探索結果から最短経路を再現 Position backTracer = Goal; while (dist>1){ --dist; backTracer = backTracer.Nearbys.First(pos => maze[pos.X,pos.Y] == dist); maze[backTracer.X, backTracer.Y] = -2; } //////////////////// 最短経路こみのアスキー地図に変換 char[,] outMaze = new char[width, height]; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { outMaze[x, y] = maze[x, y] == -2 ? '$' : maze[x, y] == -1 ? '*' : ' '; } } outMaze[Start.X, Start.Y] = 'S'; outMaze[Goal.X, Goal.Y] = 'G'; ////////////////////// 結果は標準出力に。 for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) Console.Write(outMaze[x, y]); Console.WriteLine(); } Console.ReadLine(); } /// <summary> /// 探索する。SG間の道のりを返す(道のり=SGが隣接しているなら1) /// </summary> private static int Search(int[,] maze, Position Start) { List<Position> FrontLine = new List<Position>(); FrontLine.Add(Start); int dist = 1; for (; ; ) { List<Position> NextFrontLine = new List<Position>(); foreach (var pos in FrontLine) { foreach (var nextPos in pos.Nearbys) { if (nextPos == Goal) return dist; if (maze[nextPos.X, nextPos.Y] == 0) { maze[nextPos.X, nextPos.Y] = dist; NextFrontLine.Add(nextPos); } } } FrontLine = NextFrontLine; ++dist; } } } struct Position { public readonly int X, Y; public Position(int x, int y) { X = x; Y = y; } public IEnumerable<Position> Nearbys { get { return new[]{ new Position(X-1,Y), new Position(X,Y-1), new Position(X+1,Y), new Position(X,Y+1), }; } } public static bool operator==(Position p1, Position p2){ return p1.X == p2.X && p1.Y == p2.Y; } public static bool operator!=(Position p1, Position p2){ return p1.X != p2.X || p1.Y != p2.Y; } } }
platinumで吐き出せるFMFを読み取るためクラスを置いておく。特に反省はしてない。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Data; namespace RPG { class MapFile { //FMFファイルのヘッダー struct FMFHeader { public string dwIdentifier; // ファイル識別子 'FMF_' public int dwSize; // ヘッダを除いたデータサイズ public int dwWidth; // マップの横幅 public int dwHeight; // マップの高さ public byte byChipWidth; // マップチップ1つの幅(pixel) public byte byChipHeight; // マップチップ1つの高さ(pixel) public byte byLayerCount; // レイヤーの数 public byte byBitCount; // レイヤデータのビットカウント } private FileStream fs; private BinaryReader br; private FMFHeader _head; private byte[] _data8 = null; private short[] _data16 = null; public int width { get { return _head.dwWidth; } } public int height { get { return _head.dwHeight; } } public int chip_width { get { return _head.byChipWidth; } } public int chip_height { get { return _head.byChipHeight; } } //マップファイルを読み込む。 //エラーが起きた場合は例外を投げます public void Load(String fname) { try { fs = new FileStream(fname, FileMode.Open); br = new BinaryReader(fs); //識別子を確認する _head.dwIdentifier = new String(br.ReadChars(4)); if (_head.dwIdentifier != "FMF_") { throw new Exception("ファイルが壊れています"); } //ヘッダーの残りの情報を読み込む _head.dwSize = br.ReadInt32(); _head.dwWidth = br.ReadInt32(); _head.dwHeight = br.ReadInt32(); _head.byChipWidth = br.ReadByte(); _head.byChipHeight = br.ReadByte(); _head.byLayerCount = br.ReadByte(); _head.byBitCount = br.ReadByte(); switch (_head.byBitCount) { case 8: //8bit layer _data8 = br.ReadBytes(_head.dwSize); break; case 16: //16it layer int count = _head.dwSize / 2; _data16 = new short[count]; for(int i = 0; i < count; i++) _data16[i] = br.ReadInt16(); break; } } catch(Exception ex) { throw ex; } finally { br.Close(); } } //マップファイルを閉じます public void close() { //読み込んだデータを破棄する _data8 = null; _data16 = null; } //マップファイルからチップ番号を取得します public int getValue(int layer_index, int x, int y) { if (_data8 == null &amp;&amp; _data16 == null) return -1; if (layer_index >= _head.byLayerCount || x >= _head.dwWidth || y >= _head.dwHeight) return -1; int index = 0; int layer_offset = getLayerAddr(layer_index); switch (_head.byBitCount) { case 8: //8bit layer index = _data8[layer_offset + x + y * _head.dwWidth]; break; case 16: //16it layer index = _data16[layer_offset + x + y * _head.dwWidth]; break; } return index; } //該当レイヤーが存在する_dataのindexを返す private int getLayerAddr(int layer_index) { if (layer_index >= _head.byLayerCount || (_data8 == null &amp;&amp; _data16 == null)) return -1; return _head.dwWidth * _head.dwHeight * layer_index; } } }
#訂正