using System;
using System.Collections.Generic;
using System.Linq;
// Q067 https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_C&lang=jp
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("4");
WillReturn.Add("0 0");
WillReturn.Add("3 1");
WillReturn.Add("2 3");
WillReturn.Add("0 3");
WillReturn.Add("3");
WillReturn.Add("2 1");
WillReturn.Add("0 2");
WillReturn.Add("3 2");
//2
//1
//0
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
struct PointDef
{
internal double X;
internal double Y;
}
static List<PointDef> mXYInfoList = new List<PointDef>();
static List<PointDef> mQueryInfoList = new List<PointDef>();
static void Main()
{
List<string> InputList = GetInputList();
int N = int.Parse(InputList[0]);
double[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(X => double.Parse(X)).ToArray();
foreach (string EachStr in InputList.Skip(1).Take(N)) {
SplitAct(EachStr);
PointDef WillAdd;
WillAdd.X = wkArr[0];
WillAdd.Y = wkArr[1];
mXYInfoList.Add(WillAdd);
}
foreach (string EachStr in InputList.Skip(1 + N + 1)) {
SplitAct(EachStr);
PointDef WillAdd;
WillAdd.X = wkArr[0];
WillAdd.Y = wkArr[1];
mQueryInfoList.Add(WillAdd);
}
foreach (PointDef EachQueryInfo in mQueryInfoList) {
if (OnSegment(EachQueryInfo)) {
Console.WriteLine(1);
}
else if (IsNaihou(EachQueryInfo)) {
Console.WriteLine(2);
}
else {
Console.WriteLine(0);
}
}
}
// 座標を引数として、多角形の辺上の座標かを返す
static bool OnSegment(PointDef pPoint)
{
for (int I = 0; I <= mXYInfoList.Count - 1; I++) {
PointDef FromPos = mXYInfoList[I];
int ToInd = I + 1;
if (mXYInfoList.Count - 1 < ToInd) {
ToInd = 0;
}
PointDef ToPos = mXYInfoList[ToInd];
if (CCW(FromPos, ToPos, pPoint) == 0) {
return true;
}
}
return false;
}
static int CCW(PointDef pPointA, PointDef pPointB, PointDef pPointC)
{
const int COUNTER_CLOCKWISE = 1;
const int CLOCKWISE = -1;
const int ONLINE_BACK = 2;
const int ONLINE_FRONT = -2;
const int ON_SEGMENT = 0;
PointDef VectorA = SetVector(pPointA, pPointB);
PointDef VectorB = SetVector(pPointA, pPointC);
// 外積 A*Bを求める
double Cross = DeriveCross(VectorA, VectorB);
// Aの半時計回りの方向にBが存在する
if (Cross > 0) {
return COUNTER_CLOCKWISE;
}
// Aの時計回りの方向にBが存在する
if (Cross < 0) {
return CLOCKWISE;
}
// 3点が1直線にある場合
// 内積がマイナスなら、ベクトルの向きは反対
double Dot = DeriveDot(VectorA, VectorB);
if (Dot < 0) {
return ONLINE_BACK;
}
double NormA = DeriveNorm(VectorA);
double NormB = DeriveNorm(VectorB);
if (NormA < NormB) {
return ONLINE_FRONT;
}
return ON_SEGMENT;
}
// 座標を引数として、多角形に内包してるかを返す
static bool IsNaihou(PointDef pPoint)
{
double RadSum = 0D;
for (int I = 0; I <= mXYInfoList.Count - 1; I++) {
PointDef FromPos = mXYInfoList[I];
int ToInd = I + 1;
if (mXYInfoList.Count - 1 < ToInd) {
ToInd = 0;
}
PointDef ToPos = mXYInfoList[ToInd];
PointDef Vector1 = SetVector(pPoint, FromPos);
PointDef Vector2 = SetVector(pPoint, ToPos);
double Dot = DeriveDot(Vector1, Vector2);
double CosVal = Dot / DeriveABS(Vector1) / DeriveABS(Vector2);
if (CosVal >= 1D) CosVal = 1D;
double Theta = Math.Acos(CosVal);
double Cross = DeriveCross(Vector1, Vector2);
if (Cross < 0) Theta *= -1D;
RadSum += Theta;
}
return RadSum >= 3.14D;
}
// 始点と終点の座標を引数として、始点から終点へのベクトルを返す
static PointDef SetVector(PointDef pStaPoint, PointDef pEndPoint)
{
PointDef WillReturn;
WillReturn.X = pEndPoint.X - pStaPoint.X;
WillReturn.Y = pEndPoint.Y - pStaPoint.Y;
return WillReturn;
}
// 内積を求める
static double DeriveDot(PointDef pVector1, PointDef pVector2)
{
return pVector1.X * pVector2.X + pVector1.Y * pVector2.Y;
}
// 外積を求める
static double DeriveCross(PointDef pVector1, PointDef pVector2)
{
return pVector1.X * pVector2.Y - pVector1.Y * pVector2.X;
}
// ベクトルの大きさを求める
static double DeriveABS(PointDef pVector)
{
double wkNorm = DeriveNorm(pVector);
double wkSqrt = Math.Sqrt(wkNorm);
return wkSqrt;
}
// ベクトルのNormを求める
static double DeriveNorm(PointDef pVector)
{
return pVector.X * pVector.X + pVector.Y * pVector.Y;
}
}