/*
ye mera template hai
apna khud likho bc :P
*/

/*
Author : Sarvagya Agarwal
*/

#include<bits/stdc++.h>
using namespace std;

//defines
#define openin freopen("input.txt","r",stdin)
#define openout freopen("output.txt","w",stdout)
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ll long long
#define int long long
#define mod 1000000007
#define repr(i,x,y) for (__typeof(x) i=x;i>=y;i--)
#define rep(i,x,y) for (__typeof(x) i=x;i<=y;i++)
#define all(c) (c).begin(),(c).end()
#define ff first
#define ss second
#define pb push_back
#define mp make_pair

/* Print pair */
template <typename T,typename S>
ostream & operator << (ostream &os , const pair<T,S> &v) {
    os << "(" ;
    os << v.first << "," << v.second << ")" ;
    return os ;
}
/* Print vector */
template <typename T>
ostream & operator << (ostream &os , const vector<T> &v) {
    os << "[" ;
    int sz = v.size() ;
    for(int i = 0 ; i < sz ; ++i) {
        os << v[i] ;
        if(i!=sz-1)os << "," ;
    }
    os << "]\n" ;
    return os ;
}
/* Print set */
template <typename T>
ostream & operator << (ostream &os , const set<T> &v) {
    T last = *v.rbegin() ;
    os << "[" ;
    for(auto it : v) {
        os << it  ;
        if(it != last) os << "," ;
    }
    os << "]\n" ;
    return os ;
}
/* Print Map */
template <typename T,typename S>
ostream & operator << (ostream &os , const map<T,S> &v) {
    for(auto it : v) {
        os << it.first << " : " << it.second << "\n" ;
    }
    return os ;
}
int power(int a , int b)
{
    int res = 1 ;
    while(b)
    {
        if(b%2) {
            res = (res * a) % mod ;
        }
        b/=2 ;
        a = (a*a) % mod ;
    }
    return res ;
}

//debug
#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
		cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
		const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif
int n ;
int d[35][35] ;
bool vis[35][35] ;
bool valid(int r,int c)
{
    return r >= 0 && r < n && c >=0 && c < n ;
}
int solve(int a,int b)
{
    int x = 0 , y = 0 ;
    queue<pair<int,int> > q ;
    memset(d,-1,sizeof(d)) ;
    memset(vis,false,sizeof(vis)) ;
    d[x][y] = 0 ;
    vis[x][y] = true ;
    q.push({x,y}) ;
    while(!q.empty()) {
        auto node = q.front() ; q.pop() ;
        if(node.ff == n-1 && node.ss == n-1) break ;
        for(int i = -1 ; i <= 1 ; i += 2) {
            for(int j = -1 ; j <= 1 ; j += 2) {
                int x2 = node.ff + a*i , y2 = node.ss + b*j ;
                if(valid(x2,y2) && vis[x2][y2]==false) {
                    vis[x2][y2] = true ;
                    d[x2][y2] = d[node.ff][node.ss] + 1 ;
                    q.push({x2,y2}) ;
                }
                x2 = node.ff + b*i , y2 = node.ss + a*j;
                if(valid(x2,y2) && vis[x2][y2]==false) {
                    vis[x2][y2] = true ;
                    d[x2][y2] = d[node.ff][node.ss] + 1 ;
                    q.push({x2,y2}) ;
                }
            }
        }
    }
    if(d[n-1][n-1] == mod) return -1 ;
    return d[n-1][n-1] ;
}
int32_t main()
{
    fast;
    cin >> n ;
    rep(a,1,n-1)
    {
        rep(b,1,n-1)
        {
            cout << solve(a,b) << " " ;
        }
        cout << endl ;
    }
    return 0;
}