朝日新聞2006年6月30日パズル横丁解答

プログラムの実行結果は以下の通り。

8 1 2 8 1 2 8 1 2 
7 9 3 7 9 3 7 9 3 
6 5 4 6 5 4 6 5 4 
8 1 2 8 1 2 8 1 2 
7 9 3 7 9 3 7 9 3 
6 5 4 6 5 4 6 5 4 
8 1 2 8 1 2 8 1 2 
7 9 3 7 9 3 7 9 3 
6 5 4 6 5 4 6 5 4 
FIND

但し答えはこれだけでなく沢山ある。出題意図がよく判らない。

真ん中の数字は9になり他の数字にはならないので,「真ん中の数字は何か?」が本当の出題意図なのかもしれない。

プログラムのソースは以下の通り。

#include "puzutl.h"

int mat[9][9];
YesNo ynFind = YES;             // 解が見つかった?

void pad( int irow, int icol, int val) 
{
  if( irow < 0 || irow >= 9) return; // 範囲外
  if( icol < 0 || icol >= 9) return;
  if(!(mat[irow][icol]==0||mat[irow][icol]==val)) {
    // 既に値が設定されていて,設定しようとする値と異なれば問題あり
    pe( "ERROR [%d][%d] : %d => %d\n", irow, icol, mat[irow][icol], val);
    ynFind = NO;
  }
  if( mat[irow][icol]) return;  // 既に値が設定されている場所
  mat[irow][icol] = val;        // 新しい値を設定する。
  pad( irow+3, icol+0, mat[irow][icol]); // 3つ右に同じ値を設定する。
  pad( irow-3, icol+0, mat[irow][icol]); // 3つ左に同じ値を設定する。
  pad( irow+0, icol+3, mat[irow][icol]); // 3つ下に同じ値を設定する。
  pad( irow+0, icol-3, mat[irow][icol]); // 3つ上に同じ値を設定する。
}
void pad_start( int irow, int icol)
{
  pad( irow+3, icol+0, mat[irow][icol]);
  pad( irow-3, icol+0, mat[irow][icol]);
  pad( irow+0, icol+3, mat[irow][icol]);
  pad( irow+0, icol-3, mat[irow][icol]);
}

YesNo check( int irow, int icol) // 3x3が正しいか?
{
  int twice[9+1] = {0};
  for( int row=0; row< 3; row++) {
    for( int col=0; col< 3; col++) {
      if( ++twice[mat[irow+row][icol+col]] > 1) return    NO;
    }
  }
  return    YES;
}

int main( int argc, cstring argv[])
{
  // 初期状態を設定する。
  mat[0][0] = 8;
  mat[4][0] = 7;
  mat[8][0] = 6;
  mat[0][4] = 1;
  mat[0][8] = 2;
  mat[4][8] = 3;
  mat[8][4] = 5;
  mat[8][8] = 4;
  // 3個先を同じ数字で埋める。
  pad_start( 0, 0);
  pad_start( 4, 0);
  pad_start( 8, 0);
  pad_start( 0, 4);
  pad_start( 0, 8);
  pad_start( 4, 8);
  pad_start( 8, 4);
  pad_start( 8, 8);
  // 最初の3x3に9を設定できる所を探し,見つかれば同じ処理で9を埋める。
  int irow, icol;
  for( irow=0; irow< 3; irow++) {
    for( icol=0; icol< 3; icol++) {
      if( mat[irow][icol] == 0) {
        mat[irow][icol] = 9;
        pad_start(irow,icol);
      }
    }
  }
  if( !ynFind) return 0;        // 既にエラーがあればダメ。
  // 現在の設定値を出力してみる。
  for( irow=0; irow< 9; irow++) {
    for( icol=0; icol< 9; icol++) {
      ps( "%d ", mat[irow][icol]);
      if( mat[irow][icol] == 0) ynFind = NO;
    }
    ps( "\n");
  }
  // 念のため全ての3x3をチェックする
  for( irow=0; irow< 6; irow++) {
    for( icol=0; icol< 6; icol++) {
      if( !check( irow, icol)) ynFind = NO;
    }
  }
  if( ynFind) ps( "FIND\n");
  return    0;
}