////////////////////////////////
// Amidakuji Class Test Program
////////////////////////////////
using System;

namespace TestGhostLeg
{
	//アプリケーションクラス
	public class App
	{
		//アミダクジ配列の列数、行数
		static int col = 8, row = 16;
		//Amidakujiクラスインスタンスの生成
		static Amidakuji adk = new Amidakuji(col, row);

		[STAThread]
		public static void Main()
		{
			//adk.Generate(col, row);	//↑の行を引数無しで宣言した後、このように再設定できる。
			Console.WriteLine("今回の縦棒数は{0}、段数は{1}です。", adk.Bars, adk.Steps);

			//横棒を引く
			bool cont = true;
			Console.Write("これから横棒を追加します。\r\n");
			while(cont)
			{
				//アミダクジの表示
				DispGL();
				DrawHorBar();
				Console.Write("横棒の追加を終了しますか？（yまたはYを入力してください。）:");
				string yn = Console.ReadLine();
				if(yn == "y" || yn == "Y")
					break;
			}

			Console.Write("\r\n");
			for(int i = 0; i < col; i++)
			{
				Console.WriteLine("縦棒{0}の結果は{1}でした。 ", i, adk.CheckResult(i));
				//アミダクジの表示
				DispGL();
				Console.Read();
			}

			//表示の為
			Console.Read();
		}

		//アミダクジの表示
		public static void DispGL()
		{
			for(int j = 0; j < row; j++)
			{
				for(int i = 0; i < col; i++)
					Console.Write("{0} ", adk.GetData(i, j));
				Console.Write("\r\n");
			}
		}

		//横棒を引く
		public static bool DrawHorBar()
		{
			string num;
			int s, e, r;
			Console.Write("開始列（0－{0}）は？:", adk.Bars - 1);
			num = Console.ReadLine();
			if(!Int32.TryParse(num, out s))
			{
				Console.WriteLine("整数ではありません。");
				return false;
			}
			Console.Write("終了列（左右いずれかの隣接列）は？:");
			num = Console.ReadLine();
			if(!Int32.TryParse(num, out e))
			{
				Console.WriteLine("整数ではありません。");
				return false;
			}
			Console.Write("行（0－{0}）は？:", adk.Steps - 1);
			num = Console.ReadLine();
			if(!Int32.TryParse(num, out r))
			{
				Console.WriteLine("整数ではありません。");
				return false;
			}
			if((s < 0 || s >= col) || (e < 0 || e >= col) || (r < 0 || r >= row))
			{
				Console.WriteLine("領域外です。");
				return false;
			}
			if((s == e) || ((s - e) > 1) || ((e - s) > 1))
			{
				Console.WriteLine("開始列と終了列が同じ、または離れすぎています。");
				return false;
			}
			if(e > s)
			{
				if(!adk.StepL2R(s, r))
				{
					Console.WriteLine("位置が不正で横棒を引けません。");
					return false;
				}
			}
			else
			{
				if(!adk.StepR2L(s, r))
				{
					Console.WriteLine("位置が不正で横棒を引けません。");
					return false;
				}
			}
			return true;
		}
	}

	public class Amidakuji					//アミダクジクラス
	{
		//Amidakujiクラスフィールド
		public int Bars {get; set;}			//縦棒数－アミダクジ配列の列数（横棒数）
		public int Steps {get; set;}		//アミダクジの段数－アミダクジ配列の行数
		public int Goal {get; set;}			//当たりの列
		private int[,] Data = null;			//アミダクジデータ配列
		//コンストラクター
		public Amidakuji()					//引数無し
		{
			Init();
		}
		public Amidakuji(int col, int row)	//縦棒数と段数を指定
		{
			Init();
			Generate(col, row);
		}
		//初期化メソッド
		public void Init()
		{
			Bars = 1;						//アミダクジの縦棒数初期値
			Steps = 16;						//アミダクジの段数（横棒数）初期値
			Data = null;					//アミダクジデータ配列
		}
		//アミダクジ配列生成メソッド
		public void Generate(int col, int row)
		{
			Bars = col;
			Steps = row;
			if(Data != null)
				Data = null;				//アミダクジデータ配列の再初期化
			Data = new int[Bars, Steps];	//アミダクジデータ配列の設定
			for(int i = 0; i < Bars; i++)
				for(int j = 0; j < Steps; j++)
					Data[i, j] = 0;			//アミダクジデータ配列データの初期化
		}
		//アミダクジデータ配列データの取得
		public int GetData(int col, int row)
		{
			return Data[col, row];
		}
		//アミダクジに横棒を左から右に引く
		public bool StepL2R(int s, int row)	//s列と(s + 1)列の間に横棒を引く
		{
			if(row < 0 || row >= Steps)		//縦の範囲外
				return false;
			if(s < 0 ||						//横の範囲外
				s >= Bars - 1)				//一番右の列の右に横棒は引けない
				return false;
			if(Data[s, row] != 0)			//既に横棒が引かれている
				return false;
			Data[s, row] = 1;				//横棒の左半分
			Data[s + 1, row] = 2;			//横棒の右半分
			return true;
		}
		//アミダクジに横棒を右から左に引く
		public bool StepR2L(int s, int row)	//s列と(s - 1)列の間に横棒を引く
		{
			if(row < 0 || row >= Steps)		//縦の範囲外
				return false;
			if(s <= 0 ||					//一番左の列の左に横棒は引けない
				s >= Bars)					//横の範囲外
				return false;
			if(Data[s, row] != 0)			//既に横棒が引かれている
				return false;
			Data[s, row] = 2;				//横棒の左半分
			Data[s - 1, row] = 1;			//横棒の右半分
			return true;
		}
		//縦棒のアミダクジの結果を返す
		public int CheckResult(int c)
		{
			int result = c;
			//アミダクジ全体で赤棒を元に戻す
			for(int i = 0; i < Bars; i++)
			{
				for(int j = 0; j < Steps; j++)
				{
					switch(Data[i, j])
					{
						case 4:
							Data[i, j] = 0;
							break;
						case 5:
						case 8:
							Data[i, j] = 1;
							break;
						case 6:
						case 7:
							Data[i, j] = 2;
							break;
						default:
							break;
					}
				}
			}
			//経路を赤棒で示す
			for(int i = 0; i < Steps; i++)
			{
				switch(Data[result, i])
				{
					case 0:
						Data[result, i] = 4;
						break;
					case 1:
						Data[result, i] = 5;
						result++;
						Data[result, i] = 6;
						break;
					case 2:
						Data[result, i] = 7;
						result--;
						Data[result, i] = 8;
						break;
					default:
						break;
				}
			}
			return result;
		}
	}
}
