|
SDcheck.pl
#!/usr/local/bin/perl
# 数独問題の類似度をチェックするプログラム(V3.0)
# (c)copyleft 2013-2-2 coded by shun kinoshita / knuhs
my %SDpool;
# 初期設定
my @datalist = ( 'SDdata.txt' , 'SDdata2.txt' ); # 問題集ファイル(適当に書き替える)
my $Debug = 1; # =1 なら内部情報を出力する。=0 なら出力しない
print "** 類似の数独問題が存在するかどうか検査します。\n";
# 問題データの読込み
my $total = 0; # 問題の総数を記録する
foreach my $fname ( @datalist )
{
print "\* $fname start..... ";
open( SuUDOKU, $fname ) || die "開けません。$!";
my $SDcounter = 0; # 各ファイルに含まれる問題の数を記録する
while( <SuUDOKU> )
{
chomp; # 改行コードを削除
next unless $_ ; # 空白行は読み飛ばす
$SDcounter++;
( my $SDname, my $SDdata ) = ( m/^(.*?)\t(.*)$/ ); # 問題名と初期値データを取り出す
# 初期値データから、各ブロックに属する初期値列を求め“キー”として用いる
$SDdata =~ m/(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})(\d{3})/;
my @data = ( $1.$4.$7, $2.$5.$8, $3.$6.$9, $10.$13.$16, $11.$14.$17, $12.$15.$18, $19.$22.$25, $20.$23.$26, $21.$24.$27 );
@data = map { join '', sort split '', $_ } @data;
$_ = join '', sort map { s/0(?!$)//g; $_ } @data; # キーをソートし標準形式にする
$i = ++$SDpool{$_}[0]; # キーを登録し出現回数を記録する
$SDpool{$_}[$i][0] = $SDname; # キーの基に問題名と
$SDpool{$_}[$i][1] = $SDdata; # 初期値データを保存する
}
print "($SDcounter個)\n"; # 各ファイル毎の問題の数を表示
$total += $SDcounter; # 問題の総数を記録する
close( SuUDOKU );
}
# 結果の判定
print "** 検査結果 ** (計 $total個の問題を検査しました)\n";
my $none = 1; # 類似問題がない(初期設定)
foreach my $sdkey( keys %SDpool ) # キーを取り出し
{
my $count = $SDpool{$sdkey}[0]; # 出現回数から類似問題がないか調べる
next if $count==1; # 重複なし(=1)ならば次へ
print "\n* 類似の問題が $count個見つかりました。\n";
for( my $index=1; $index<=$count; $index++ )
{
my $initVal = $SDpool{$sdkey}[$index][1]; # 初期設定値を取り出す
print " ($index)$SDpool{$sdkey}[$index][0]\n"; # 問題名を出力
print " [0]キー値=\"$sdkey\"\n [1]初期値=\"$initVal\"\n" if $Debug;
# キー値と初期値を出力
# 初期値データから各行の値を求める
$initVal =~ m/(\d{9})(\d{9})(\d{9})(\d{9})(\d{9})(\d{9})(\d{9})(\d{9})(\d{9})/;
my @data = ( $1, $2, $3, $4, $5, $6, $7, $8, $9 ); # 行毎の初期値から行情報を作る
@data = map { join '', sort split '', $_ } @data; # 行情報を標準形式にする
my $Col = join '', sort map { s/0(?!$)//g; $_ } @data;
$SDpool{$sdkey}[$index][2] = $Col; # 行情報の保存
# 初期値データから各列の値を求める
@data = split '', $initVal;
my @RC;
for ( my $n = 0; $n <= 8; $n++ ) # 行と列を入れ替える
{ $RC[$n] = join '', @data[$n, $n+9, $n+18, $n+27, $n+36, $n+45, $n+54, $n+63, $n+72]; }
@data = map { join '', sort split '', $_ } @RC; # 列情報を標準形式にする
my $Row = join '', sort map { s/0(?!$)//g; $_ } @data;
$SDpool{$sdkey}[$index][3] = $Row; # 列情報の保存
print " [2]行情報=\"$Col\"\n [3]列情報=\"$Row\"\n\n" if $Debug;
# 行情報と列情報を出力
}
$none = 0; # 類似問題あり
# 最終判定
for( my $i = 1; $i <= $count; $i++ )
{ for( my $j = 1; $j <= $count; $j++ )
{ next if $i<= $j;
if ( $SDpool{$sdkey}[$i][1] eq $SDpool{$sdkey}[$j][1] )
{ print " ・($j)と($i)は、まったく同じ問題です。\n"; }
elsif ( $SDpool{$sdkey}[$i][2] eq $SDpool{$sdkey}[$j][2]
|| $SDpool{$sdkey}[$i][3] eq $SDpool{$sdkey}[$j][3] )
{ print " ・($j)と($i)は、ブロックまたは行を入れ替えただけの同じ問題です。\n"; }
elsif ( $SDpool{$sdkey}[$i][3] eq $SDpool{$sdkey}[$j][2]
|| $SDpool{$sdkey}[$i][2] eq $SDpool{$sdkey}[$j][3] )
{ print " ・($j)と($i)は、行と列を入れ替えただけの同じ問題です。\n"; }
else{ print " ・($j)と($i)は、似ていますが別物です。\n"; }
}
}
}
print "\n 類似の問題はありません。" if $none;
print "\n*** チェック終了 ***";
|
|
![](/cgi-bin/user/skinoshita/Count.cgi?df=cp05.count)
|
|