#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
int n;
vector<int> point[2];
vector<pair<long long, int> > area[2], vec[4];
long long query(int type, int i, int j, int k) {
  printf("%d %d %d %d\n", type, i, j, k);
  fflush(stdout);
  long long res;
  scanf("%lld", &res);
  return res;
}
int main() {
  scanf("%d", &n);
  for (int i = 3; i <= n; i++) {
    if (query(2, 1, 2, i) < 0)
      point[0].emplace_back(i);
    else
      point[1].emplace_back(i);
  }
  for (int i = 0; i < point[0].size(); i++)
    area[0].emplace_back(make_pair(query(1, 1, 2, point[0][i]), point[0][i]));
  for (int i = 0; i < point[1].size(); i++)
    area[1].emplace_back(make_pair(query(1, 1, 2, point[1][i]), point[1][i]));
  pair<long long, int> L, R;
  for (int i = 0; i < area[0].size(); i++) L = max(L, area[0][i]);
  for (int i = 0; i < area[1].size(); i++) R = max(R, area[1][i]);
  for (int i = 0; i < point[0].size(); i++) {
    if (point[0][i] == L.second) continue;
    if (query(2, 1, L.second, point[0][i]) < 0)
      vec[0].push_back(area[0][i]);
    else
      vec[1].push_back(area[0][i]);
  }
  for (int i = 0; i < point[1].size(); i++) {
    if (point[1][i] == R.second) continue;
    if (query(2, 1, R.second, point[1][i]) < 0)
      vec[2].emplace_back(area[1][i]);
    else
      vec[3].emplace_back(area[1][i]);
  }
  for (int i = 0; i <= 3; i++) sort(vec[i].begin(), vec[i].end());
  printf("0 1 ");
  for (int i = 0; i < vec[0].size(); i++) printf("%d ", vec[0][i].second);
  if (L.second) printf("%d ", L.second);
  for (int i = vec[1].size() - 1; i >= 0; i--) printf("%d ", vec[1][i].second);
  printf("2 ");
  for (int i = 0; i < vec[2].size(); i++) printf("%d ", vec[2][i].second);
  if (R.second) printf("%d ", R.second);
  for (int i = vec[3].size() - 1; i >= 0; i--) printf("%d ", vec[3][i].second);
  printf("\n");
  fflush(stdout);
}
