#include <bits/stdc++.h>
using namespace std;
struct R {
  long long lx, hx, ly, hy;
  R(long long lx, long long hx, long long ly, long long hy)
      : lx(lx), hx(hx), ly(ly), hy(hy) {}
  double area() { return 1.0 * (hx - lx + 1) * (hy - ly + 1); }
  double area(long long chx) { return 1.0 * (chx - lx + 1) * (hy - ly + 1); }
  double area3(long long qx, long long qy) {
    if (lx > qx || ly > qy) return 0;
    return 1.0 * (min(hx, qx) - lx + 1) * (min(hy, qy) - ly + 1);
  }
};
vector<R> opt;
pair<long long, long long> calcmove() {
  long long hx = opt.back().hx, hy = opt.back().hy;
  pair<long long, long long> ret = make_pair(hx, hy);
  double l = 0, h = 1.0;
  double area = 0;
  for (int i = (0); i < (((int)(opt).size())); ++i) area += opt[i].area();
  for (int rep = (0); rep < (20); ++rep) {
    double m = l + (h - l) / 2;
    long long qx = -1, qy = -1;
    {
      double have = 0;
      for (int i = ((int)(opt).size()) - 1; i >= 0; --i) {
        double cur = opt[i].area();
        if (have + cur >= m * area) {
          double frac = (m * area - have) / cur;
          long long dx = (long long)ceil(frac * (opt[i].hx - opt[i].lx + 1));
          qx = opt[i].hx - dx + 1;
          break;
        }
        have += cur;
      }
      assert(qx != -1);
    }
    {
      double have = 0;
      for (int i = (0); i < (((int)(opt).size())); ++i) {
        double cur = opt[i].area(hx);
        if (have + cur >= m * area) {
          double frac = (m * area - have) / cur;
          long long dy = (long long)ceil(frac * (opt[i].hy - opt[i].ly + 1));
          qy = opt[i].hy - dy + 1;
          break;
        }
        have += cur;
      }
      assert(qy != -1);
    }
    {
      double have = 0;
      for (int i = (0); i < (((int)(opt).size())); ++i)
        have += opt[i].area3(qx, qy);
      double frac = have / area;
      if (frac >= m)
        l = m, ret = make_pair(qx, qy);
      else
        h = m;
    }
  }
  return ret;
}
bool local = false;
pair<long long, long long> localans;
int nq;
int query(pair<long long, long long> move) {
  ++nq;
  if (local) {
    if (localans == move) return 0;
    vector<int> poss;
    if (move.first < localans.first) poss.push_back(1);
    if (move.second < localans.second) poss.push_back(2);
    if (move.first > localans.first || move.second > localans.second)
      poss.push_back(3);
    assert(((int)(poss).size()) != 0);
    int idx = rand() % ((int)(poss).size());
    return poss[idx];
  } else {
    printf("%lld %lld\n", move.first, move.second);
    fflush(stdout);
    int ret;
    scanf("%d", &ret);
    return ret;
  }
}
void solve(long long lim) {
  opt.clear();
  opt.push_back(R(1, lim, 1, lim));
  while (((int)(opt).size()) != 0) {
    for (int i = (1); i < (((int)(opt).size())); ++i)
      assert(opt[i - 1].hx < opt[i].lx);
    pair<long long, long long> move = calcmove();
    int ans = query(make_pair(lim - move.first + 1, lim - move.second + 1));
    if (ans == 0) break;
    vector<R> nopt;
    if (ans == 1)
      for (int i = (0); i < (((int)(opt).size())); ++i)
        if (opt[i].lx < move.first)
          nopt.push_back(R(opt[i].lx, min(opt[i].hx, move.first - 1), opt[i].ly,
                           opt[i].hy));
    if (ans == 2)
      for (int i = (0); i < (((int)(opt).size())); ++i)
        if (opt[i].ly < move.second)
          nopt.push_back(R(opt[i].lx, opt[i].hx, opt[i].ly,
                           min(opt[i].hy, move.second - 1)));
    if (ans == 3)
      for (int i = (0); i < (((int)(opt).size())); ++i) {
        if (opt[i].lx > move.first || opt[i].ly > move.second) {
          nopt.push_back(opt[i]);
          continue;
        }
        if (opt[i].hy > move.second && opt[i].lx <= move.first)
          nopt.push_back(R(opt[i].lx, min(opt[i].hx, move.first),
                           move.second + 1, opt[i].hy));
        if (opt[i].hx > move.first)
          nopt.push_back(R(max(move.first + 1, opt[i].lx), opt[i].hx, opt[i].ly,
                           opt[i].hy));
      }
    opt = nopt;
  }
}
void run() {
  long long lim;
  scanf("%lld", &lim);
  solve(lim);
}
long long myrand() {
  return rand() % 1000 * (long long)1000000 * 1000000000 +
         rand() % 1000 * (long long)1000 * 1000000000 +
         rand() % 1000 * (long long)1000000000 + rand() % 1000 * 1000000 +
         rand() % 1000 * 1000 + rand() % 1000 + 1;
}
void stress() {
  int mxq = 0;
  for (int rep = (0); rep < (10000); ++rep) {
    long long lim = (long long)1000000000 * 1000000000;
    local = true;
    localans = make_pair(myrand(), myrand());
    nq = 0;
    int seed = rand() % 1000 * 1000 + rand() % 1000;
    srand(seed);
    solve(lim);
    if (nq > mxq) mxq = nq, printf("%d\n", nq);
  }
}
void test() {
  long long lim = (long long)1000000000000000000LL;
  local = true;
  localans = make_pair(477659980146085779LL, 521095928229275533LL);
  nq = 0;
  srand(918951);
  printf("lim=%lld localans=(%lld,%lld)\n", lim, localans.first,
         localans.second);
  solve(lim);
  printf("%d\n", nq);
}
int main() {
  run();
  return 0;
}
