キラー数独ソルバーを構築する


9

通常の数独は難しいと思っていましたが、今度はキラー数独を試してください!

キラー数独のゲームでは、あなたはまったく番号を与えられていません。代わりに、特定の数になると言われる地域が与えられます。Wikipediaの次の例を考えてみます。

キラー数独パズル

そしてその解決策:

キラー数独パズルソリューション

作成するプログラムは、リージョンを表す81文字のシーケンスとそれに続く一連の数字で構成される形式になります。次に、シーケンスの各数値は、「A」、「B」などから始まる各文字領域の数値の合計を表します。

次に、解を表す81桁のシーケンスを出力します。

たとえば、上のパズルの例には次の入力があります。

AABBBCDEFGGHHCCDEFGGIICJKKFLMMINJKOFLPPQNJOORSPTQNUVVRSTTQWUUXXSYZWWaaXXSYZWbbbcc
3 15 22 4 16 15 25 17 9 8 20 6 14 17 17 13 20 12 27 6 20 6 10 14 8 16 15 13 17

結果の出力は次のようになります。

215647398368952174794381652586274931142593867973816425821739546659428713437165289

入力は有効であり、領域は常にA、B、...、Y、Z、a、b、...、zの順に表示されると想定できます。

(動作する最も短いコードが優先されます。)


どのようにして競争に勝ちますか?最短コード?最速のコード?
beary605 2013年

最短コード。[ 文字数の制限が1文字不足しています。]
Joe Z. 2013年

そして、52を超える地域がある場合、何をしますか?
リスター氏2013年

45を超える地域はないと想定できます。
Joe Z. 2013年

1
ケージ内で番号を繰り返すことはできますか?
Peter Taylor

回答:


4

R-378文字

想定

x="AABBBCDEFGGHHCCDEFGGIICJKKFLMMINJKOFLPPQNJOORSPTQNUVVRSTTQWUUXXSYZWWaaXXSYZWbbbcc"
y="3 15 22 4 16 15 25 17 9 8 20 6 14 17 17 13 20 12 27 6 20 6 10 14 8 16 15 13 17"

378文字:

z=strsplit
v=sapply
R=rep(1:9,9)
C=rep(1:9,e=9)
N=1+(R-1)%/%3+3*(C-1)%/%3
G=z(x,"")[[1]]
M=as.integer(z(y," ")[[1]])[order(unique(G))]
s=c(1,rep(NA,80))
i=1
repeat if({n=function(g)!any(v(split(s,g),function(x)any(duplicated(x,i=NA))))
S=v(split(s,G),sum)
n(R)&&n(C)&&n(N)&&n(G)&&all(is.na(S)|S==M)}){if(i==81)break;i=i+1;s[i]=1}else{while(s[i]==9){s[i]=NA
i=i-1};s[i]=s[i]+1}
s

2,964,690回の反復の後、私の控えめなPCで期待されるソリューションに到達するのに約1時間かかります。


脱ゴルフ:

ROWS   <- rep(1:9, 9)
COLS   <- rep(1:9, each = 9)
NONETS <- 1 + (ROWS - 1) %/% 3 + 3 * (COLS - 1) %/% 3
CAGES  <- strsplit(x, "")[[1]]
SUMS   <- as.integer(strsplit(y, " ")[[1]])[order(unique(CAGES))]

is.valid <- function(sol) {

   has.no.repeats <- function(sol, grouping) {
      !any(vapply(split(sol, grouping),
                  function(x) any(duplicated(x, incomparables = NA)),
                  logical(1)))
   }
   has.exp.sum <- function(sol, grouping, exp.sums) {
      sums <- vapply(split(sol, grouping), sum, integer(1))
      all(is.na(sums) | sums == exp.sums)
   }

   has.no.repeats(sol, ROWS  ) &&
   has.no.repeats(sol, COLS  ) &&
   has.no.repeats(sol, NONETS) &&
   has.no.repeats(sol, CAGES ) &&
   has.exp.sum(sol, CAGES, SUMS)        
}

sol <- c(1L, rep(NA, 80)) # start by putting a 1
i <- 1L                   # in the first cell
it <- 0L

repeat {
   it <- it + 1L
   if (it %% 100L == 0L) print(sol)
   if(is.valid(sol)) {         # if everything looks good
      if (i == 81L) break         # we are either done
      i <- i + 1L                 # or we move to the next cell
      sol[i] <- 1L                # and make it a 1
   } else {                    # otherwise
      while (sol[i] == 9L) {      # while 9s are found
         sol[i] <- NA             # replace them with NA
         i <- i - 1L              # and move back to the previous cell
      }
      sol[i] <- sol[i] + 1L       # when a non-9 is found, increase it
   }                           # repeat
}
sol

4

GolfScript、138文字

n%~[~]:N;1/:P.&:L;9..*?{(.[{.9%)\9/}81*;]:§;L{.`{\~@@=*}+[P§]zip%{+}*\L?N==}%§9/..zip+\3/{{3/}%zip{{+}*}%}%{+}*+{.&,9=}%+1-,!{§puts}*.}do;

これは、GolfScriptの強力な数独ソルバーです。上記の例で示したように、2行のSTDINへの入力を想定しています。

注意:パズルの説明は実行時間を制限しないため、速度よりも小さなコードサイズを優先しました。コードはすべての9 ^ 81グリッド構成をテストして、遅いコンピューターでは時間がかかる可能性があるソリューションを探します;-)


確認できますか?:P
ジョーZ.

@ JoeZeng、4x4に微調整するのは簡単そうです。ここでは、テストケースがあります:AABBCADEFFDDGGGG 6 7 4 8 2 3 10
ピーター・テイラー

@PeterTaylorテストケースには4つの異なる有効なソリューションがあります。
Joe Z. 2013年

4

Ruby、970文字

A,B=gets,gets.split
L=[]
R=[]
U=[]
D=[]
N=[]
C=[]
S=[]
O=[0]*81
z='A'
(0..324).map{|j|U<<j;D<<j;R<<(j+1)%325;L<<(j+324)%325;N<<j;C<<j;S<<0}
X=->s,j,c,cf,n{j<81?(z==A[j]?(0..8).map{|i|X[s-1-i,j+1,c+[i],cf+[1+j,1+81+27*i+j/9,1+81+27*i+9+j%9,1+81+27*i+18+j/3%3+j/27*3],n+[i+1]]}:X[s,j+1,c,cf,n+[0]]if s>=0):(h=U.size;cf.uniq.sort.map{|l|N<<n;L<<(L[h]||h);R<<h;U<<U[l];D<<l;C<<l;S[l]+=1;L[R[-1]]=R[L[-1]]=U[D[-1]]=D[U[-1]]=L.size-1}if s==0)}
Y=->c{L[R[c]]=L[c];R[L[c]]=R[c];i=D[c];(j=R[i];(U[D[j]]=U[j];D[U[j]]=D[j];S[C[j]]-=1;j=R[j])while j!=i;i=D[i])while i!=c}
Z=->c{i=U[c];(j=L[i];(S[C[j]]+=1;U[D[j]]=j;D[U[j]]=j;j=L[j])while j!=i;i=U[i])while i!=c;L[R[c]]=c;R[L[c]]=c}
B.map{|k|X[k.to_i,0,[],[],[]];z=z=='Z'?'a':z.next}
s=->k{c=R[0];c<1?($><<(O[0,k].map{|s|N[s]}.transpose.map &:max)*""):(g=S[b=c];g=S[b=c]if S[c]<g while 0<c=R[c];Y[b];r=D[b];(O[k]=r;j=R[r];(Y[C[j]];j=R[j])while j!=r;s[k+1];r=O[k];c=C[r];j=L[r];(Z[C[j]];j=L[j])while j!=r;r=D[r])while r!=b;Z[b])}
s[0]

上記のRubyコードは、GolfScriptサブスクリプションとは逆です。かなり長い(まだ完全にはゴルフされていない)が、速度が最適化されている。上記のキラー数独は1秒未満で解決されます(私のオリジナルのJavaバージョンでは数ミリ秒しかありませんでした)。ソルバー自体は、KnuthのDLXアルゴリズムの基本的な実装です。

入力はSTDINで2行として指定する必要があります。例(オンライン):

> AABBBCDEFGGHHCCDEFGGIICJKKFLMMINJKOFLPPQNJOORSPTQNUVVRSTTQWUUXXSYZWWaaXXSYZWbbbcc
3 15 22 4 16 15 25 17 9 8 20 6 14 17 17 13 20 12 27 6 20 6 10 14 8 16 15 13 17

215647398368952174794381652586274931142593867973816425821739546659428713437165289
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.