//#pragma GCC optimize ("O3", "unroll-loops")
//#pragma GCC target ("avx2")
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int, int>
#define PLL pair<LL, LL>
#define all_of(v) (v).begin(), (v).end()
#define sort_unique(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define fi first
#define se second
const int MAXN = 105;
//const LL INF = (LL) 1e9 + 8763;
//const LL MOD = (LL) 998244353;
using namespace std;
//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int n, conn[MAXN], ans[MAXN][MAXN];

int ask1(int u, int v) {
	// if u -> v is correct, return 1
	int rep;
	cout << "1 " << u << ' ' << v << endl;
//	assert(u != v);
	cin >> rep;
//	assert(rep != -1);
	return rep;
}

int ask2(int u, vector<vector<int>> &S) {
	// if u reaches v, return 1
	vector<int> V;
	for (auto &x : S) {
		for (auto &y : x) {
			V.push_back(y);
		}
	}
	
	int rep;
	cout << "2 " << u << ' ' << V.size();
	for (int x : V) cout << ' ' << x;
	cout << endl;
	
//	assert(u != v);
	cin >> rep;
//	assert(rep != -1);
	return rep;
}

vector<int> msort(int l, int r) {
//	cout << "Get " << l << ' ' << r << '\n';
	vector<int> ord;
	if (l == r) {
		ord.push_back(l);
		return ord;
	}
	int mid = (l + r) / 2;
	auto L = msort(l, mid);
	auto R = msort(mid + 1, r);
	
	reverse(all_of(L));
	reverse(all_of(R));
	while (!L.empty() || !R.empty()) {
		if (L.empty()) {
			ord.push_back(R.back());
			R.pop_back();
		}
		else if (R.empty()) {
			ord.push_back(L.back());
			L.pop_back();
		}
		else {
			int dir = ask1(L.back(), R.back());
			if (dir == 1) {
				ord.push_back(L.back());
				L.pop_back();
			}
			else {
				ord.push_back(R.back());
				R.pop_back();	
			}
		}
	}
	return ord;
}

struct DSU {
	int pa[MAXN], sz[MAXN];
	void init(int n) {
		for (int i = 0; i <= n; i++) {
			pa[i] = i;
			sz[i] = 1;
		}
	}
	int find(int x) {
		return x == pa[x] ? x : find(pa[x]); // Add compression by yourself
	}
	int merge(int x, int y) {
		x = find(x); y = find(y);
		if (x == y) return 0;
		if (sz[x] < sz[y]) swap(x, y);
		sz[x] += sz[y];
		pa[y] = x;
		return 1;
	}
} dsu;

void solve() {
	cin >> n;
	for (int i = 0; i <= n; i++) {
		for (int j = 0; j <= n; j++) {
			ans[i][j] = 0;
		}
	}
	
	// phase 1
	vector<int> ord = msort(0, n - 1);
//	cout << "ORD:";for (int x :ord)cout << ' ' << x; cout << '\n';
	
	// phase 2
	dsu.init(n);
	vector<vector<int>> S;
	for (int i = 0; i < n; i++) {
		int v = ord[i];
		vector<int> cur({v});
		while (!S.empty()) {
			if (ask2(v, S)) {
				auto vec = S.back();
				for (int u : vec) cur.push_back(u);
				dsu.merge(v, vec.back());
				S.pop_back();
			}
			else {
				break;
			}
		}
		S.push_back(cur);
	}
	
	// ans
	for (int i = 0; i < n; i++) {
		for (int j = i; j < n; j++) {
			ans[ord[i]][ord[j]] = 1;
			if (i != j) {
				if (dsu.find(ord[i]) == dsu.find(ord[j])) {
					ans[ord[j]][ord[i]] = 1;
				}
			}
		}
	}
	
	// out
	cout << "3" << endl;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cout << ans[i][j];
		}
		cout << endl;
	}
	
	int jud;
	cin >> jud;
//	assert(jud == 1);
}

int main() {
	int tc = 1;
	cin >> tc;
	for (int i = 1; i <= tc; i++) {
		solve();
	}
 
	return 0;
}