using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("3 3");
WillReturn.Add("1 1");
WillReturn.Add("3 3");
WillReturn.Add("..#");
WillReturn.Add("#.#");
WillReturn.Add("#..");
//2
}
else if (InputPattern == "Input2") {
WillReturn.Add("3 3");
WillReturn.Add("2 1");
WillReturn.Add("2 3");
WillReturn.Add("#.#");
WillReturn.Add("...");
WillReturn.Add("#.#");
//0
}
else if (InputPattern == "Input3") {
WillReturn.Add("4 6");
WillReturn.Add("2 1");
WillReturn.Add("1 5");
WillReturn.Add("...#..");
WillReturn.Add(".#.##.");
WillReturn.Add(".#....");
WillReturn.Add("...##.");
//5
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static int mSta_Y;
static int mSta_X;
static int mGoal_Y;
static int mGoal_X;
static char[,] mBanArr;
static int UB_X;
static int UB_Y;
static void Main()
{
List<string> InputList = GetInputList();
int[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => int.Parse(pX)).ToArray();
SplitAct(InputList[1]);
mSta_Y = wkArr[0] - 1;
mSta_X = wkArr[1] - 1;
SplitAct(InputList[2]);
mGoal_Y = wkArr[0] - 1;
mGoal_X = wkArr[1] - 1;
mBanArr = CreateBanArr(InputList.Skip(3));
UB_X = mBanArr.GetUpperBound(0);
UB_Y = mBanArr.GetUpperBound(1);
ExecBFS();
}
struct JyoutaiDef
{
internal int Vect_X;
internal int Vect_Y;
internal int Curr_X;
internal int Curr_Y;
internal int Cost;
internal int Level;
}
static void ExecBFS()
{
var InsLinkedList = new LinkedList<JyoutaiDef>();
JyoutaiDef WillEnque;
WillEnque.Vect_X = 0;
WillEnque.Vect_Y = 0;
WillEnque.Curr_X = mSta_X;
WillEnque.Curr_Y = mSta_Y;
WillEnque.Cost = 0;
WillEnque.Level = 0;
InsLinkedList.AddFirst(WillEnque);
// 最小コスト[座標のハッシュ値]
var EdakiriDict = new Dictionary<int, int>();
while (InsLinkedList.Count > 0) {
JyoutaiDef Dequeued = InsLinkedList.First.Value;
InsLinkedList.RemoveFirst();
if (Dequeued.Curr_X == mGoal_X && Dequeued.Curr_Y == mGoal_Y) {
Console.WriteLine(Dequeued.Cost);
break;
}
Action<int, int> EnqueuAct = (pVect_X, pVect_Y) =>
{
// 逆ベクトルは不可
int Rev_X = Dequeued.Vect_X * (-1);
int Rev_Y = Dequeued.Vect_Y * (-1);
if (pVect_X == Rev_X && pVect_Y == Rev_Y) {
return;
}
int NewX = Dequeued.Curr_X + pVect_X;
int NewY = Dequeued.Curr_Y + pVect_Y;
if (NewX < 0 || UB_X < NewX) return;
if (NewY < 0 || UB_Y < NewY) return;
if (mBanArr[NewX, NewY] == '#') return;
bool AddCost = false;
if (Dequeued.Level > 0) {
if (Dequeued.Vect_X != pVect_X || Dequeued.Vect_Y != pVect_Y) {
AddCost = true;
}
}
WillEnque.Vect_X = pVect_X;
WillEnque.Vect_Y = pVect_Y;
WillEnque.Curr_X = NewX;
WillEnque.Curr_Y = NewY;
WillEnque.Cost = Dequeued.Cost;
WillEnque.Level = Dequeued.Level + 1;
if (AddCost) {
WillEnque.Cost++;
}
int Hash = GetHash(WillEnque.Curr_X, WillEnque.Curr_Y);
if (EdakiriDict.ContainsKey(Hash)) {
// ベクトルが違う可能性があるので、
// 等しい場合は許可だが、真に大きい場合は不可
if (EdakiriDict[Hash] < WillEnque.Cost) {
return;
}
}
EdakiriDict[Hash] = WillEnque.Cost;
if (AddCost) {
InsLinkedList.AddLast(WillEnque);
}
else {
InsLinkedList.AddFirst(WillEnque);
}
};
EnqueuAct(0, -1);
EnqueuAct(0, +1);
EnqueuAct(-1, 0);
EnqueuAct(+1, 0);
}
}
static int GetHash(int pX, int pY)
{
return pX * 10000 + pY;
}
////////////////////////////////////////////////////////////////
// IEnumerable<string>をcharの2次元配列に設定する
////////////////////////////////////////////////////////////////
static char[,] CreateBanArr(IEnumerable<string> pStrEnum)
{
var StrList = pStrEnum.ToList();
if (StrList.Count == 0) {
return new char[0, 0];
}
int UB_X = StrList[0].Length - 1;
int UB_Y = StrList.Count - 1;
char[,] WillReturn = new char[UB_X + 1, UB_Y + 1];
for (int Y = 0; Y <= UB_Y; Y++) {
for (int X = 0; X <= UB_X; X++) {
WillReturn[X, Y] = StrList[Y][X];
}
}
return WillReturn;
}
}