永遠のループに陥るか、それとも自殺するかの救われないストーリーである。
何が悩んだかってループ判定ですよ、ループ判定。
上手くいくまで両手の関節の数くらいは心折れたと思う。
using System; using System.Linq; using System.IO; using System.Text; using System.Collections; using System.Collections.Generic; /** * Auto-generated code below aims at helping you parse * the standard input according to the problem statement. **/ class Solution { public static Bender ben; static void Main(string[] args) { //勉三さんの生成 ben = new Bender(); //地図の表示 ben.ShowMap(); //ループ判定 bool loop = true; //ゲームループ while (loop) { //勉三さんの死orループ判定 loop = !ben.PonkotsuAI(); } //勉三さんの歴史を語る ben.TalkHistory(); } /// <summary> /// 勉三さんクラス /// </summary> public class Bender { //地図 private Map map; //移動履歴 private List<string> MoveRecord; //方向(文字)と移動方向(座標)をくっつけたもの private Dictionary<string, Point> Dic = new Dictionary<string, Point>() { {"SOUTH", new Point(0, 1)}, {"EAST", new Point(1, 0)}, {"NORTH", new Point(0, -1)}, {"WEST", new Point(-1, 0)}, }; //移動方向 private string[] Way = { "SOUTH", "EAST", "NORTH", "WEST" }; //現在の座標 private Point Coordinate; //現在の移動方向 private string Direction; //破壊者モードフラグ private bool Breaker; //壊したブロックの数 private int BlockBreakNum; //リバースモードフラグ private bool Reverse; //生存フラグ private bool Live; //ループフラグ private bool Loop; /// <summary> /// コンストラクタ /// </summary> public Bender() { this.map = new Map(); this.MoveRecord = new List<string>(); //地図のスタートポイントを設定 this.Coordinate = map.StartPoint; //最初は南向き this.Direction = "SOUTH"; this.Breaker = false; this.BlockBreakNum = 0; this.Reverse = false; this.Live = true; this.Loop = false; } /// <summary> /// ポンコツ頭脳 /// </summary> /// <returns>bool : 終了か続行か</returns> public bool PonkotsuAI() { //移動方向の決定 this.DetermineDirection(); //移動 this.Move(); //シンボルの反応 this.LookSymbol(); //ループのチェック this.CheckLoop(); //終了か続行か return this.IsEnd(); } /// <summary> /// 移動方向の決定 /// </summary> public void DetermineDirection() { //現在方向の一歩先を見る char c = map.GetSymbol(ben.Coordinate + ben.Dic[ben.Direction]); //障害物アリなら移動方向の変更 if (ben.isObstacles(c) == true) this.SearchAround(ben.Coordinate, 1); } /// <summary> /// シンボルの反応 /// </summary> public void LookSymbol() { //現在位置のシンボルを得る char c = map.GetSymbol(ben.Coordinate); switch (c) { case 'X': //ブロックの破壊 this.BreakObjectX(); break; case 'B': //破壊者モード on <=> off this.Breaker = !this.Breaker; break; case 'I': //リバースモード on <=> off this.Reverse = !this.Reverse; break; case '$': //自殺 this.Live = false; break; case 'S': //南へ this.Direction = "SOUTH"; break; case 'E': //東へ this.Direction = "EAST"; break; case 'N': //北へ。White Illumination this.Direction = "NORTH"; break; case 'W': //西へ this.Direction = "WEST"; break; case 'T': // *おおっと! テレポーター* this.OnTeleport(); break; } } /// <summary> /// 移動 /// </summary> public void Move() { //履歴を記録 this.WriteHistory(); //方向に従って座標を移動 this.Coordinate += this.Dic[this.Direction]; } /// <summary> /// 障害物判定 /// </summary> /// <param name="sbl">char : 地図上のシンボル</param> /// <returns>bool : true障害物 false障害ではない</returns> public bool isObstacles(char sbl) { switch (sbl) { case '#': //壁 return true; case 'X': //ブロックは破壊者モードなら無視 if (this.Breaker != true) return true; else return false; } //壁やブロック以外は障害物ではない return false; } /// <summary> /// ブロックの破壊 /// </summary> private void BreakObjectX() { //地図の書き換え this.map.Chips[this.Coordinate.X, this.Coordinate.Y] = ' '; //ブロックの破壊数を+1 this.BlockBreakNum++; } /// <summary> /// テレポーターの上 /// </summary> private void OnTeleport() { //別のテレポーターに移動 if (Point.Equal(this.Coordinate, this.map.Telepoter[0]) == true) this.Coordinate = this.map.Telepoter[1]; else if (Point.Equal(this.Coordinate, this.map.Telepoter[1]) == true) this.Coordinate = this.map.Telepoter[0]; else Console.Error.WriteLine("Teleport error!"); //石の中にいる } /// <summary> /// 移動可能かどうか周囲を探索 /// </summary> /// <param name="p">Point : 座標</param> /// <param name="i">int : 再帰回数制限</param> /// <returns>char : 周囲のシンボル</returns> private char SearchAround(Point p, int i) { //シンボルを返す if (i == 0) return map.GetSymbol(p); //シンボル char c; //探索する順番 int start, end, cre; //探索する順番を決める this.SetOrder(out start, out end, out cre); for (int j = start; j != end; j += cre) { //シンボルを取得 c = this.SearchAround(p + this.Dic[this.Way[j]], i - 1); //障害物でなければ、その方向に移動方向を設定 if (ben.isObstacles(c) == false) { this.Direction = this.Way[j]; break; } } //とりあえず return ' '; } /// <summary> /// 周囲を探索する順番を設定する /// </summary> /// <param name="start">out int : 開始番号</param> /// <param name="end">out int : 終了番号</param> /// <param name="cre">out int : 増減加減</param> private void SetOrder(out int start, out int end, out int cre) { if (ben.Reverse == true) { //リバースモードなら逆順 start = this.Way.Length - 1; end = 0; cre = -1; } else { //リバースモードでないなら普通に start = 0; end = this.Way.Length - 1; cre = 1; } } /// <summary> /// 勉三さん、履歴を語る /// </summary> public void TalkHistory() { //ループしてなければ if (this.Loop == false) { //移動履歴から方向だけ抽出して出力 foreach (string s in this.MoveRecord) { string[] d = s.Split(' '); Console.WriteLine(d[0]); } } else { //ループしていればLOOPを出力 Console.WriteLine("LOOP"); } } /// <summary> /// ループチェッカー /// </summary> private void CheckLoop() { //現在のステータスと同じ状態が履歴にあればループと判定 if (this.MoveRecord.Exists(x => x == this.NowStatus()) == true) { this.Loop = true; } } /// <summary> /// 終了判定 /// </summary> /// <returns>bool : true終了 false続行</returns> private bool IsEnd() { //死ぬかループしてたらtrue、それ以外はfalse if (this.Live == false | this.Loop == true) return true; else return false; } /// <summary> /// 履歴を書き込む /// </summary> public void WriteHistory() { //現在のステータスを記録 this.MoveRecord.Add(this.NowStatus()); } /// <summary> /// 現在のステータス /// </summary> /// <returns>string : 現在のステータス</returns> private string NowStatus() { return string.Format("{0} {1}{2}{3}{4}", this.Direction, this.Coordinate, this.Breaker, this.Reverse, this.BlockBreakNum); } /// <summary> /// マップの表示 /// </summary> public void ShowMap() { this.map.ShowMap(); } } /// <summary> /// 座標クラス /// </summary> public class Point { public int X; public int Y; /// <summary> /// コンストラクタ /// </summary> /// <param name="x">x座標</param> /// <param name="y">y座標</param> public Point(int x, int y) { this.X = x; this.Y = y; } /// <summary> /// 2つの座標が等しいか調べる /// </summary> /// <param name="p1">Point : 比較対象1</param> /// <param name="p2">Point : 比較対象2</param> /// <returns>bool : true等しい false等しくない</returns> public static bool Equal(Point p1, Point p2) { if (p1.X == p2.X & p1.Y == p2.Y) return true; else return false; } /// <summary> /// +演算子 /// </summary> /// <param name="p1">Point : 足すやつ</param> /// <param name="p2">Point : 足すやつ</param> /// <returns>Point : コンゴトモヨロシク</returns> public static Point operator +(Point p1, Point p2) { return new Point(p1.X + p2.X, p1.Y + p2.Y); } /// <summary> /// 文字列にする /// </summary> /// <returns>string : 座標の文字列</returns> public override string ToString() { return string.Format("{0} {1}", this.X, this.Y); } } /// <summary> /// 地図クラス /// </summary> public class Map { //地図本体 public char[,] Chips; //縦幅 public int Width; //横幅 public int Height; //スタート座標 public Point StartPoint; //テレポーター座標 public Point[] Telepoter = new Point[2]; /// <summary> /// コンストラクタ /// </summary> public Map() { //地図を作る this.CreateMap(); //シンボルを読み込む this.GetMapSymbols(); } /// <summary> /// 地図を作る /// </summary> private void CreateMap() { string[] inputs = Console.ReadLine().Split(' '); this.Height = int.Parse(inputs[0]); this.Width = int.Parse(inputs[1]); this.Chips = new char[this.Width, this.Height]; } /// <summary> /// シンボルを読み込む /// </summary> private void GetMapSymbols() { for (int y = 0; y < this.Height; y++) { string row = Console.ReadLine(); for (int x = 0; x < this.Width; x++) { //地図にシンボルを書き込む this.Chips[x, y] = row[x]; //スタート位置を発見 if (row[x] == '@') { this.StartPoint = new Point(x, y); } //テレポーターを発見 if (row[x] == 'T') { if (this.Telepoter[0] == null) this.Telepoter[0] = new Point(x, y); else this.Telepoter[1] = new Point(x, y); } } } } /// <summary> /// シンボルを取得する /// </summary> /// <param name="p">Point : 座標</param> /// <returns>char : シンボル</returns> public char GetSymbol(Point p) { return this.Chips[p.X, p.Y]; } /// <summary> /// 地図を表示 /// </summary> public void ShowMap() { Console.Error.WriteLine("***Symbols Map***"); for (int y = 0; y < this.Height; y++) { for (int x = 0; x < this.Width; x++) { Console.Error.Write(this.Chips[x, y]); } Console.Error.WriteLine(""); } } } }
- 作者: カースティーン・ロブソン,ルース・ラッセル他
- 出版社/メーカー: ポプラ社
- 発売日: 2013/09/05
- メディア: 単行本
- この商品を含むブログを見る