#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <string>
#include <bitset>
#include <cstdio>
#include <limits>
#include <vector>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <unordered_map>

//generate all possible unique destinations from (0,0) in an integer no of steps
            //stop once no new unique destination can be obtained this will be at some step k
            //there are a max of n^2 unique destinations, since we only generate new destinations at each level of tree
            //k is guaranteed to be finite

using namespace std;

int getMinSteps(int a, int b, int n){
     //bool hasBeenDiscovered[n][n];
    
    std::vector<std::vector<bool>> hasBeenDiscovered(n,std::vector<bool>(n, false));
    
    int minSteps=-1,x=0,y=0,currentLevel=1;
    pair<int,int> currentNode;
    pair<int,int> lastNodeCopyInCurrentLevel,endOfQueue;
    queue<pair<int,int>> nextNodesInBFS;//stores the coordinates of the next node as we traverse the tree BFS style
    int TotalReachableNodes=1;
    //possible displacements (deltax, deltay);
    std::pair<int,int> * displacements=new pair<int,int>[8];
    displacements[0]=make_pair(a,b);
    displacements[1]=make_pair(a,-b);
    displacements[2]=make_pair(-a,b);
    displacements[3]=make_pair(-a,-b);
    displacements[4]=make_pair(b,a);
    displacements[5]=make_pair(b,-a);
    displacements[6]=make_pair(-b,a);
    displacements[7]=make_pair(-b,-a);
    //initialise queue
    for(int i=0;i!=8;i++){
        int x2=x+displacements[i].first,y2=y+displacements[i].second;
        if(x2>=0 && x2<n && y2>=0 && y2<n && !hasBeenDiscovered[x2][y2]) {
            //if(a==1 && b==4)  cout<<"* node "<<x2<<"  "<<y2<<endl;
            hasBeenDiscovered[x2][y2]=true;
            nextNodesInBFS.push(make_pair(x2,y2));//only store new/undiscovered destinations in queue
            endOfQueue=make_pair(x2,y2);
            //DEBUG++TotalReachableNodes;
        }          
    }
    lastNodeCopyInCurrentLevel=endOfQueue;
    //generate all children but stop if one reaches desired destination otherwise stop when all possible cells discovered
    while(!nextNodesInBFS.empty()){
        currentNode=nextNodesInBFS.front();
        x=currentNode.first,y=currentNode.second;
        //if(a==1 && b==4)  cout<<"** node "<<x<<"  "<<y<<endl;
        //determine if current node is desired destination
        if(x==n-1 && y==n-1){
            minSteps=currentLevel;
            break;
        }
        //reaching here means current node is not desired destination
        
        //add all undiscovered destinations reachable from currentNode to queue
       for(int i=0;i!=8;i++){
           int x2=x+displacements[i].first,y2=y+displacements[i].second;
           //if(a==1 && b==4)  cout<<"* considered"<<x2<<"  "<<y2<<" "<<hasBeenDiscovered[x2][y2]<<endl;
           if(x2>=0 && x2<n && y2>=0 && y2<n && !hasBeenDiscovered[x2][y2]) {              
               hasBeenDiscovered[x2][y2]=true;
               nextNodesInBFS.push(make_pair(x2,y2));//only store new/undiscovered destinations in queue
               endOfQueue=make_pair(x2,y2);
            }         
        }
        //mark node as visited and remove from queue
        nextNodesInBFS.pop();
        //update level
        if(currentNode==lastNodeCopyInCurrentLevel){
            ++currentLevel;
            lastNodeCopyInCurrentLevel=endOfQueue;
        }        
    }
    
    //DEBUGcout<<TotalReachableNodes<<endl;
    return minSteps;
}

int main(){
    int n,temp=1;
    cin >> n;
    int results[n-1][n-1]={0};
    
    for(int a=1;a!=n;a++){
        for(int b=temp;b!=n;b++){
            int minSteps=getMinSteps(a,b,n);
            results[a-1][b-1]=minSteps;
            if(a!=b) results[b-1][a-1]=minSteps;//(a,b) & (b,a) result in the same possible moves from any source            
            
        }
        ++temp;
    }
    
    //print results
    for(int i=0;i!=n-1;i++){
        for(int j=0;j!=n-1;j++) {
            const char endChar=(j==n-2)?'\n':' ';
            cout<<results[i][j]<<endChar;
        }
    }
    return 0;
}