//dennismv
#include
<iostream>
#include
<vector>
#include
<iomanip>
#include
<cmath>
using
namespace std;
#define
FOR(i,n) for (int
i=0;i<(int)n;i++)
#define
FORN(i,a,b) for (int
i=a;i<=b;i++)
const
int MAX=10;
int
primes[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199};
const
int numPrimes=46;
int
storedGrid[MAX][MAX];
bool
gridIsStored;
int
minSum;
bool
checkPlacement(int grid[][MAX],vector<int>
&isPrime,int row,int
col)
{
int center=grid[row][col];
if (row-1>=0 &&
!isPrime[center+grid[row-1][col]]) return
false;
if (col-1>=0 &&
!isPrime[center+grid[row][col-1]]) return
false;
return true;
}
bool
optimalSum(int grid[][MAX],int
g)
{
int sum=0;
FOR(i,g)FOR(j,g)sum+=grid[i][j];
int optimalSum=g*g*(1+g*g)/2;
return (sum==optimalSum);
}
void
showGrid(int grid[][MAX],int
g,int count)
{
cout<<"Matt,
here is puzzle #"<<count<<":"<<endl;
int fieldWidth=0;
FOR(i,g)FOR(j,g) if (grid[i][j]>fieldWidth)
fieldWidth=grid[i][j];
fieldWidth=(int)floor(log((double)fieldWidth)/log((double)10)+1);
FOR(i,g)
{
cout<<setw(fieldWidth)<<grid[i][0];
FORN(j,1,g-1) cout<<setw(fieldWidth+1)<<grid[i][j];
cout<<endl;
}
}
bool
minGridSum(int grid[][MAX],int
g)
{
int sum=0;
FOR(i,g)FOR(j,g)sum+=grid[i][j];
if (minSum<=sum)
return false;
minSum=sum;
return true;
}
bool
placeNext(int grid[][MAX],int
g,bool used[],vector<int>
&isPrime,int gridPlace=0)
{
if (gridPlace==g*g)
{
if (optimalSum(grid,g))
{
//cout<<"OPTIMALE!\n";
return true;
}
if (minGridSum(grid,g))
//found next smallest grid!!
{
//store grid!
//showGrid(grid,g,1);
gridIsStored=true;
FOR(i,g)FOR(j,g) storedGrid[i][j]=grid[i][j];
}
return false;
}
//stuff
int final;
if (g>4) final=g*g;
else final=2*g*g;
FOR(i,final)
{
if (used[i])
continue;
used[i]=true;
grid[gridPlace/g][gridPlace%g]=i+1;
if (checkPlacement(grid,isPrime,gridPlace/g,gridPlace%g)
&& placeNext(grid,g,used,isPrime,gridPlace+1)) return
true;
grid[gridPlace/g][gridPlace%g]=0;
used[i]=false;
}
return false;
}
int
main()
{
int grid[MAX][MAX];
bool used[MAX*MAX];
//get prime index ready
vector<int>
isPrime(primes[numPrimes-1]+1);
FOR(i,numPrimes)
isPrime[primes[i]]=true;
int n,count=1,g;
while (cin>>g>>n && g!=0)
{
gridIsStored=false;
minSum=300000;
//min sum
FOR(i,100) used[i]=0;
grid[0][0]=n;
//place n in top left
used[n-1]=true;
//and mark it used
//place remaining elements
if (count>1) cout<<endl;
if (placeNext(grid,g,used,isPrime,1))
showGrid(grid,g,count);
//optimal grid
else if
(gridIsStored) showGrid(storedGrid,g,count);
//optimized grid (not optimal but as far as we
could get)
else cout<<"Yo,
Matt! That puzzle #"<<count<<",
it was not cool!"<<endl;
//sorry,ya no grid Matt!
used[n-1]=false;
count++;
}
}