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("1 1");
WillReturn.Add("5 6");
//2
}
else if (InputPattern == "Input2") {
WillReturn.Add("1 1");
WillReturn.Add("1 200001");
//2
}
else if (InputPattern == "Input3") {
WillReturn.Add("2 3");
WillReturn.Add("998244353 998244853");
//3
}
else if (InputPattern == "Input4") {
WillReturn.Add("1 1");
WillReturn.Add("1 1");
//0
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
int[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => int.Parse(pX)).ToArray();
SplitAct(InputList[0]);
int r1 = wkArr[0], c1 = wkArr[1];
SplitAct(InputList[1]);
int r2 = wkArr[0], c2 = wkArr[1];
// 0手の場合
if (r1 == r2 && c1 == c2) {
Console.WriteLine(0);
return;
}
// 1手の場合 (ビショップ移動を1回)
if (CanMoveBishop(r1, c1, r2, c2)) {
Console.WriteLine(1);
return;
}
// 1手の場合 (ビショップでない移動を1回)
// 座標を引数とし、ビショップでない移動で、遷移できる座標のListを返す
List<PointDef> CanMoveNonBishopList1 = DeriveCanMoveNonBishopList(r1, c1);
if (CanMoveNonBishopList1.Exists(pX => pX.X == r2 && pX.Y == c2)) {
Console.WriteLine(1);
return;
}
// 2手の場合 (ビショップ移動を2回)
int Distance = DeriveDistance(r1, c1, r2, c2);
if (Distance % 2 == 0) {
Console.WriteLine(2);
return;
}
// 2手の場合 (ビショップでない移動後に、ビショップ移動かビショップでない移動)
foreach (PointDef EachPoint in CanMoveNonBishopList1) {
// ビショップ移動
if (CanMoveBishop(EachPoint.X, EachPoint.Y, r2, c2)) {
Console.WriteLine(2);
return;
}
//ビショップでない移動
List<PointDef> CanMoveNonBishopList2 =
DeriveCanMoveNonBishopList(EachPoint.X, EachPoint.Y);
if (CanMoveNonBishopList2.Exists(pX => pX.X == r2 && pX.Y == c2)) {
Console.WriteLine(2);
return;
}
}
Console.WriteLine(3);
}
// 座標2つを引数とし、1手のビショップ移動で到達できるかを返す
static bool CanMoveBishop(int pX1, int pY1, int pX2, int pY2)
{
if (pX1 == pX2 && pY1 == pY2) return false;
int XDiff = pX2 - pX1;
int YDiff = pY2 - pY1;
// 傾きが1か-1ならOK
if (XDiff == YDiff) return true;
if (XDiff == -YDiff) return true;
return false;
}
struct PointDef
{
internal int X;
internal int Y;
}
// 座標を引数とし、ビショップでない移動で、遷移できる座標のListを返す
static List<PointDef> DeriveCanMoveNonBishopList(int pX, int pY)
{
var WillReturn = new List<PointDef>();
for (int LoopX = pX - 3; LoopX <= pX + 3; LoopX++) {
for (int LoopY = pY - 3; LoopY <= pY + 3; LoopY++) {
int Distance = DeriveDistance(LoopX, LoopY, pX, pY);
if (1 <= Distance && Distance <= 3) {
PointDef WillAdd;
WillAdd.X = LoopX;
WillAdd.Y = LoopY;
WillReturn.Add(WillAdd);
}
}
}
return WillReturn;
}
// 座標2つを引数として、マンハッタン距離を返す
static int DeriveDistance(int pX1, int pY1, int pX2, int pY2)
{
int Distance = 0; // マンハッタン距離
Distance += Math.Abs(pX1 - pX2);
Distance += Math.Abs(pY1 - pY2);
return Distance;
}
}