トップページに戻る    前の再帰with句のサンプルへ

再帰with句10 数独を解く

SQLパズル

数独を解きます。


SQL

with rec(LV,Val) as(
select 1,'080701050'
      || '002040900'
      || '930000074'
      || '800104006'
      || '006000100'
      || '700903008'
      || '240000015'
      || '007050300'
      || '050807040' from dual
union all
select LV+1,
case when substr(Val,LV,1) = '0'
     then substr(Val,1,LV-1) || to_char(cnt)
       || substr(Val,LV+1) else Val end
from rec a,(select RowNum as cnt from dict where RowNum <= 9) b
where LV <= 81
  and (substr(Val,LV,1) = '0' or cnt=1)
  and (substr(Val,LV,1) !='0'
    or (instr(substr(Val,trunc((LV-1)/9)*9+1,9),to_char(cnt)) = 0 /*横チェック*/
    and instr(substr(Val,mod(LV-1,9)+1   ,1),to_char(cnt)) = 0 /*縦チェック*/
    and instr(substr(Val,mod(LV-1,9)+1+ 9,1),to_char(cnt)) = 0
    and instr(substr(Val,mod(LV-1,9)+1+18,1),to_char(cnt)) = 0
    and instr(substr(Val,mod(LV-1,9)+1+27,1),to_char(cnt)) = 0
    and instr(substr(Val,mod(LV-1,9)+1+36,1),to_char(cnt)) = 0
    and instr(substr(Val,mod(LV-1,9)+1+45,1),to_char(cnt)) = 0
    and instr(substr(Val,mod(LV-1,9)+1+54,1),to_char(cnt)) = 0
    and instr(substr(Val,mod(LV-1,9)+1+63,1),to_char(cnt)) = 0
    and instr(substr(Val,mod(LV-1,9)+1+72,1),to_char(cnt)) = 0
    /*正方形チェック*/
    and instr(substr(Val,trunc(mod(LV-1,9)/3)*3+1+9*(trunc(trunc((LV-1)/9)/3)*3)   ,3),to_char(cnt))=0
    and instr(substr(Val,trunc(mod(LV-1,9)/3)*3+1+9*(trunc(trunc((LV-1)/9)/3)*3)+ 9,3),to_char(cnt))=0
    and instr(substr(Val,trunc(mod(LV-1,9)/3)*3+1+9*(trunc(trunc((LV-1)/9)/3)*3)+18,3),to_char(cnt))=0)))
select Val from rec
where LV = 82;


解説

手続き型言語を使ったほうが楽そうですねぇ
C#のサンプル集 8-8 数独
Javaアルゴリズムパズル 3-7 数独
DB2 SQLパズル 再帰with句10 数独を解く
PostgreSQLパズル 再帰with句10 数独を解く

実行結果
684791253572348961931526874823174596496285137715963428248639715167452389359817642

マニュアル --- substr関数
substring_lengthを指定しないと、Oracleはcharの終わりまでのすべての文字を戻します。
substring_lengthが1より小さい場合、NULLを戻します。