#include "puzutl.h"

#define ROWS    3 // ブロックサイズ
#define COLS    3
#define M       (ROWS*COLS) // 問題図の大きさ
int mat[M][M]; // 0:空きマス,1〜9:確定数字

int IsThisOK( int row, int col, int k) // mat[row][col] に k を置けるか?
{
  int rowBlock, colBlock;
  int xrow, xcol;
  for( xrow=0; xrow< M; xrow++) { // 同じ行にkが使われていないか?
    if( mat[xrow][col] == k) return 0;
  }
  for( xcol=0; xcol< M; xcol++) { // 同じ列にkが使われていないか?
    if( mat[row][xcol] == k) return 0;
  }
  // 同じブロックにkが使われていないか?
  rowBlock = row/ROWS*ROWS;
  colBlock = col/COLS*COLS;
  for( xrow=0; xrow<ROWS; xrow++) {
    for( xcol=0; xcol< COLS; xcol++) {
      if( mat[rowBlock+xrow][colBlock+xcol] == k) return 0;
    }
  }
  return    1;
}

void printdata()
{
  for( int row=0; row< M; row++) {
    for( int col=0; col< M; col++) {
      printf( "%c", ".123456789"[mat[row][col]]);
    }
    printf( "\n");
  }
}

void find( int p) // 調査位置p
{
  if( p >= M*M) {
    ps( "見つけた\n");
    printdata(); // 解答図を出力する
    return;
  }
  int row, col, k;
  row = p/M; // 調査位置pを[行][列]に変換する
  col = p%M;
  if( mat[row][col]) {
    find( p+1);
  }
  else {
    for( k=1; k<= M; k++) {
      if( IsThisOK( row, col, k)) {
        mat[row][col] = k;
        find( p+1);
        mat[row][col] = 0;
      }
    }
  }
}

YesNo setdata( int row, const char* s) // 指定行に問題を入力する
{
  int col = 0;
  while(*s && col < M) {
    if( *s == '.') {
      mat[row][col++] = 0;
    }
    else if( *s >= '1' && *s <= '9'){
      mat[row][col++] = *s - '0';
    }
    else {
      pe( "データ文字(%c,HEX:%x)を認識出来ません@行(%d)\n", *s, *s, row);
      return NO;
    }
    s++;
  }
  if( *s && col != M) {
    pe( "列数(%d)が合いません,期待値(%d)\n", col, M);
    return NO;
  }
  return YES;
}

YesNo readdata( cstring fn)
{
  if( !is_exist_file(fn)) {
    pe( "ファイル(%s)が存在しません。\n", fn);
    return NO;
  }
  TextFile tf(fn);
  cstring s;
  int row = 0;
  while( s=tf.gets()) {
    if( setdata(row,s) == NO) return NO;
    row++;
  }
  if( row != M) {
    pe( "行数(%d)が合いません。期待値(%d)\n", row, ROWS);
    return NO;
  }
  return YES;
}

int main( int argc, const char* argv[])
{
  Option opt( argc, argv);
  cstring fn = opt.argv(0);
  if( !*fn) {
    pe( "データファイルを指定して下さい\n");
    exit(0);
  }
  if( readdata( fn)) {          // 問題図を読み込む
    printdata();                // 問題図を出力する
    find( 0);                   // 左上([0][0])から虱潰しで検索する
  }
  return    0;
}