#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<set>

using namespace std;

static const int di[] = {-1,0,1,0};
static const int dj[] = {0,1,0,-1};

typedef pair<int,int> pi;

#define MAX 16
#define fr first
#define sc second
#define MAXDIR 4

//vector<pi> houses;
int houseId[MAX][MAX];
pi charch;

struct Node{
  bool isCharch;
  bool isHouse;
  int linkmax[MAXDIR];
  pi link[MAXDIR][MAX];
  bool exist[MAXDIR];
  bool cexist[MAXDIR];
  Node():isCharch(false),isHouse(false){
    for(int i=0;i<MAXDIR;++i){
      linkmax[i]=0;
      cexist[i]=exist[i]=false;
    }
  }
};

struct state{
  char ni,nj;
  char cnt;
  int vis;
  state(){}
  state(char si, char sj, char cnt, int vis):ni(si),nj(sj),cnt(cnt),vis(vis){}
};

//void bfs(Node M[][MAX], state init, int nhouse, int &ans);

inline bool isinside(int H, int W, int i, int j){
  return 0<=i&&i<H&&0<=j&&j<W;
}

class Queue{
private:
  int p;
  state *V;
public:
  Queue():p(0){V=new state[1<<20];}
  ~Queue(){delete [] V;}
  void push(const state &t){V[p++]=t;}
  state * front(){return &V[p-1];}
  void pop(){--p;}
  bool empty(){return p==0;}
};

void bfs(const Node M[][MAX], state init, int nhouse, int &ans){
  Queue qs;
  qs.push( init );
  int ni,nj;
  int housenum=0;
  int chi=charch.fr;int chj=charch.sc;
  
  for(int k = 0; k < MAXDIR; ++k){
    housenum += M[chi][chj].linkmax[k];
  }
  
  while(!qs.empty()){
    state st_now = *( qs.front() );
    ni = st_now.ni;
    nj = st_now.nj;    
    qs.pop();
    
    if( st_now.cnt == nhouse ){
      for(int l = 0; l < MAXDIR; ++l){
	if( M[ni][nj].cexist[l] ){
	  ++ans;
	  break;
	}
      }
      continue;
    }else{

      int left = housenum;
      for(int k = 0; k < MAXDIR; ++k){
	for(int v = 0; v < M[chi][chj].linkmax[k]; ++v){
	  pi hs = M[chi][chj].link[k][v];
	  left-=(bool)(st_now.vis&(1<<houseId[hs.fr][hs.sc]));
	}
      }
      if( left == 0 )
	continue ;
      
      for(int k = 0; k < MAXDIR; ++k){
	for(int v = 0; v < M[ni][nj].linkmax[k]; ++v){
	  pi next = M[ni][nj].link[k][v];
	  int mask=1<<houseId[next.fr][next.sc];
	  if( !(st_now.vis&mask) ){
	    qs.push( state(next.fr,next.sc,st_now.cnt + 1,st_now.vis|mask) );
	    break;
	  }
	}
      }
    }
  }
  return ;
}

int main()
{
  while(true){
    int ans = 0;
    int W,H;
    scanf("%d%d", &W, &H);
    if(W==0&&W==H)break;
    int iM[MAX][MAX];
    Node M[MAX][MAX];

    int nhouse=0;

    for(int i = 0; i < H; ++i){
      for(int j = 0; j < W; ++j){
	scanf("%d", &iM[i][j]);
	if(iM[i][j]==1){
	  ++nhouse;
	  houseId[i][j]=nhouse;
	  M[i][j].isHouse=true;
	}else if(iM[i][j]==2){
	  M[i][j].isCharch=true;
	  charch = pi(i,j);
	}
      }
    }
    
    for(int i = 0; i < H; ++i){
      for(int j = 0; j < W; ++j){
	for(int k = 0; k < MAXDIR; ++k){
	  int ti=i+di[k];
	  int tj=j+dj[k];
	  while(isinside(H,W,ti,tj)){
	    if(M[ti][tj].isHouse){
	      M[i][j].link[k][ M[i][j].linkmax[k]++ ] = pi(ti,tj);
	      M[i][j].exist[k]=true;
	    }else if(M[ti][tj].isCharch){
	      M[i][j].cexist[k]=true;
	    }
	    ti+=di[k];tj+=dj[k];
	  }
	}
      }
    }
    
    state init(charch.fr,charch.sc,0,0);
    bfs(M,init,nhouse,ans);
    printf("%d\n", ans);

  }
  return 0;

}

Measured memory_bytes: 1048