创建一个数独解决方案CHECKER


21

创建Sudoku解决方案CHECKER

这里有Sudoku SOLVERS的面条,但是我希望您创建一个尽可能小巧的解决方案CHECKER(代码高尔夫球)。

  • 一个有效的条目将能够采用9x9数组作为参数(通过引用传递,在命令行上序列化,或者您要采用它),或者接受输入文件,该文件是最后一行网格的九行九位数。请参阅下面的输入示例。

  • 有效输入应以10为底的数字(1-9)

  • 缺失,空,多余,非数字的位置或数字在1-9之外的位置应通过返回非零结果,打印错误或同时拒绝这两种方法而被视为无效输入。

  • 您的程序需要测试每个数字是否在每列,每行一次和每个3x3子网格中出现一次。如果通过,则返回“ 0”,否则,返回非零结果。

  • 避免使用外部资源(网站等)。

  • 如果您的解决方案是独立程序,则退出状态为退出或打印时,“通过”或“失败”分别为“ 0”或非零是可以的。

让最小的答案赢!

输入示例:

C数组:

int input[9][9]={{1,2,3,4,5,6,7,8,9},
                 {4,5,6,7,8,9,1,2,3},
                 {7,8,9,1,2,3,4,5,6},
                 {2,3,1,5,6,4,8,9,7},
                 {5,6,4,8,9,7,2,3,1},
                 {8,9,7,2,3,1,5,6,4},
                 {3,1,2,6,4,5,9,7,8},
                 {6,4,5,9,7,8,3,1,2},
                 {9,7,8,3,1,2,6,4,5}
                };

文件:

123456789
456789123
789123456
231564897
564897231
897231564
312645978
645978312
978312645

9个子网格:

+---+---+---+
|123|456|789|
|456|789|123|
|789|123|456|
+---+---+---+
|231|564|897|
|564|897|231|
|897|231|564|
+---+---+---+
|312|645|978|
|645|978|312|
|978|312|645|
+---+---+---+

Answers:


5

GolfScript,39个字符

.zip.{3/}%zip{~}%3/{[]*}%++{$10,1>=!},,

它以数组的数组作为输入(请参见在线示例),0如果它是有效的网格,则将其输出。

代码简短说明

.zip         # Copy the input array and transpose it
.{3/}%       # Split each line into 3 blocks
zip{~}%      # Transpose these blocks
3/{[]*}%     # Do the same for the lines themselves and join again
++           # Make one large list of 27 9-element arrays 
             # (9 for rows, 9 for columns, 9 for blocks)
{$10,1>=!},  # From those 27 select the ones which are not a permutation of [1 2 3 ... 9]
             #   $      -> sort
             #   10,1>  -> [1 2 3 ... 9]
             #   =!     -> not equal
,            # Count after filtering

我喜欢您代码的非零输出比“正义” 1或“ 正义”更有意义-1
David Wilkins

我真的很喜欢您的回答,但是最后我选择了不采用golfscript解决方案。我真的希望您能理解
David Wilkins 2014年

2
@DavidWilkins其实我不明白-您制定了规则(!),并且没有声明不允许GolfScript的任何地方。
2014年

您的观点完全正确...事实上,我没有任何理由不选择您的答案。表现出色
David Wilkins 2014年

10

巨蟒,103

我讨厌数独。

b = [[1,2,3,4,5,6,7,8,9],
     [4,5,6,7,8,9,1,2,3],
     [7,8,9,1,2,3,4,5,6],
     [2,3,1,5,6,4,8,9,7],
     [5,6,4,8,9,7,2,3,1],
     [8,9,7,2,3,1,5,6,4],
     [3,1,2,6,4,5,9,7,8],
     [6,4,5,9,7,8,3,1,2],
     [9,7,8,3,1,2,6,4,5]]

e=enumerate;print 243-len(set((a,t)for(i,r)in e(b)for(j,t)in e(r)for a in e([i,j,i/3*3+j/3]*(0<t<10))))

工作原理:每行,每一列和每个块都必须具有从1到9的每个数字。因此,对于每个0 <= i, j < 9,单元格i,j都在block中3*floor(i/3) + floor(j/3)。因此,有243个要满足的要求。我将每个需求都设为一个元组((item index,item type number),symbol),其中item index的数字是0到8(含)之间的数字,分别item type number是0、1或2以表示行,列或块,并且symbol是entry b[i][j]

编辑:我错误地没有检查有效的条目。现在我知道了。


0如果解决方案通过,则您的程序应该输出,而不是True
David Wilkins 2014年

@DavidWilkins有点奇怪的要求。固定。
展位

您先生,我以投票的方式投票:D
Teun Pronk 2014年

9

APL(46)

{∧/,↑∊∘Z¨(/∘(,⍵)¨↓Z∘.=,3/3⌿3 3⍴Z←⍳9),(↓⍵),↓⍉⍵}

这需要9 x 9的矩阵。可以在TryAPL上输入示例一,如下所示:

     sudoku ← ↑(1 2 3 4 5 6 7 8 9)(4 5 6 7 8 9 1 2 3)(7 8 9 1 2 3 4 5 6)(2 3 1 5 6 4 8 9 7)(5 6 4 8 9 7 2 3 1)(8 9 7 2 3 1 5 6 4)(3 1 2 6 4 5 9 7 8)(6 4 5 9 7 8 3 1 2)(9 7 8 3 1 2 6 4 5)
     {∧/,↑∊∘Z¨(/∘(,⍵)¨↓Z∘.=,3/3⌿3 3⍴Z←⍳9),(↓⍵),↓⍉⍵} sudoku
1

说明:

  • ↓⍉⍵:获取的列
  • ↓⍵:获取的行
  • 3/3⌿3 3⍴Z←⍳9:使一个3乘3包含数字矩阵19,然后一式三份在两个方向上的每个号码,给人一种9乘9矩阵与数字19指示每个组,
  • Z∘.=:每个号码19,做一个位掩码为给定组,
  • /∘(,⍵)¨:,然后分别遮盖,给予分组
  • ∊∘Z¨:对于每个子阵列,看它是否包含数字19
  • ∧/,↑:将and所有这些数字合乎逻辑。

+1好!但是3×3组可以打更多的高尔夫球。例如,这↓9 9⍴1 3 2⍉3 3 9⍴⍵等效于/∘(,⍵)¨↓Z∘.=,3/3⌿3 3⍴Z←⍳9但相当短。我确定公式甚至更短。
Tobia 2014年

此外,您可以按一维连接矩阵,并在最后执行一次拆分:↓(9 9⍴1 3 2⍉3 3 9⍴⍵)⍪⍵⍪⍉⍵
Tobia 2014年

有一个错误:此代码∊∘Z¨正在测试每个子数组(行,列或块)是否仅由数字1到9组成。它不是在测试是否代表了所有数字。您需要执行类似的操作Z∘.∊,以测试Z中的每个数字是否包含在每个子数组中。
Tobia 2014年

并且∧/,↑可以缩短为∧/∊。我完成了,我完成了!;-)
Tobia 2014年

非常紧凑,但是您错过了我马上就能看到的一个关键点:If it passes, return "0" and if not, return a non-zero result.
David Wilkins 2014年

5

Java / C#-183 / 180 181/178 173/170字节

boolean s(int[][]a){int x=0,y,j;int[]u=new int[27];for(;x<(y=9);x++)while(y>0){j=1<<a[x][--y];u[x]|=j;u[y+9]|=j;u[x/3+y/3*3+18]|=j;}for(x=0;x<27;)y+=u[x++];return y==27603;}

(更改 booleanbool为C#)

格式:

boolean s(int[][] a){
    int x=0, y, j;
    int[] u=new int[27];
    for(;x<(y=9);x++)
        while(y>0){
            j=1<<a[x][--y];
            u[x]|=j;
            u[y+9]|=j;
            u[x/3+y/3*3+18]|=j;
        }

    for(x=0;x<27;)
        y+=u[x++];

    return y==27603;
}

该方法创建一个数组 u具有27个位掩码,这些掩码代表在9个行,列和正方形中找到的数字。

然后遍历所有单元,执行操作 1 << a[x][y]以创建代表数字的位掩码,并对其进行列,行和正方形位掩码。

然后,它遍历所有27个位掩码,确保它们全部加起来为27594(1022 * 9,其中1022是存在的所有数字1-9的位掩码)。(注意y由于双循环后已经包含9,因此最终结果为27603。)

编辑:不小心留在了 %3不再需要。

编辑2:受到布莱斯·瓦格纳(Bryce Wagner)的评论的启发,该代码被压缩得更多。


C#149个字符中的算法几乎相同(但仅在允许使用Linq的情况下):bool s(int [] a){int x = 0,y,j; var u = new int [27]; while(x ++ <(y = 9))while(y> 0){j = 1 << a [x + 9 *-y]; u [x] | = j; u [y + 9] | = j; u [x / 3 + y / 3 * 3 + 18] | = j;}返回u.Sum()== 27594;}
Bryce Wagner

@BryceWagner Linq确实有用。但是,我的解决方案是针对Java,而C#是事后的想法(甚至在原始帖子中也没有提及),因此优先级较低。在决定是否使用一维数组之前,我还一开始使用了一维数组(因为示例中使用的是二维数组)。不过,您的代码给了我一些想法,以了解如何减少更多的字节。:)
Smallhacker 2014年

3

蟒蛇= 196

不是最喜欢打高尔夫球的人,但是这里有这个想法。集合非常有用。

板:

b = [[1,2,3,4,5,6,7,8,9],
     [4,5,6,7,8,9,1,2,3],
     [7,8,9,1,2,3,4,5,6],
     [2,3,1,5,6,4,8,9,7],
     [5,6,4,8,9,7,2,3,1],
     [8,9,7,2,3,1,5,6,4],
     [3,1,2,6,4,5,9,7,8],
     [6,4,5,9,7,8,3,1,2],
     [9,7,8,3,1,2,6,4,5]]

程序:

n={1,2,3,4,5,6,7,8,9};z=0
for r in b:
 if set(r)!=n:z=1
for i in zip(*b):
 if set(i)!=n:z=1
for i in (0,3,6):
 for j in (0,3,6):
  k=j+3
  if set(b[i][j:k]+b[i+1][j:k]+b[i+2][j:k])!=n:z=1
print(z)

s / {1,2,3,4,5,6,7,8,9} / set(range(1,10))/保存3个字符。
MatrixFrog 2014年

在Python 3.5中,您可以使用n={*range(1,10)},但这比挑战要新。而是使用set(range(1,10))MatrixFrog所说的。
mbomb007'9

3

Java- 385306328260个字符

编辑: 我愚蠢地误读了说明,答案必须是一个完整的程序。由于它只能是一个有效的函数,因此我将其重写和最小化为一个函数,并牢记这一点重写了我的解决方案介绍。

因此,作为对自己的挑战,我认为我想尝试做最小的Java解决方案检查器。

为此,我假设数独难题将作为java多维数组传递,如下所示:

s(new int[][] {
    {1,2,3,4,5,6,7,8,9},
    {4,5,6,7,8,9,1,2,3},
    {7,8,9,1,2,3,4,5,6},
    {2,3,1,5,6,4,8,9,7},
    {5,6,4,8,9,7,2,3,1},
    {8,9,7,2,3,1,5,6,4},
    {3,1,2,6,4,5,9,7,8},
    {6,4,5,9,7,8,3,1,2},
    {9,7,8,3,1,2,6,4,5}});

然后,我们有了实际的求解器,如果有效解,则返回“ 0”,否则返回“ 1”。

完全打高尔夫球:

int s(int[][] s){int i=0,j,k=1;long[] f=new long[9];long r=0L,c=r,g=r,z=45L,q=r;for(f[0]=1L;k<9;){f[k]=f[k-1]*49;z+=f[k++]*45;}for(;i<9;i++){for(j=0;j<9;){k=s[i][j];r+=k*f[i];c+=k*f[j];g+=k*f[j++/3+3*(i/3)];q+=5*f[k-1];}}return (r==z&&c==z&&g==z&&q==z)?0:1;}

可读性:

    int s(int[][] s) {
        int i=0,j,k=1;
        long[] f=new long[9]; 
        long r=0L,c=r,g=r,z=45L,q=r;
        for(f[0]=1L;k<9;){f[k]=f[k-1]*49;z+=f[k++]*45;}
        for(;i<9;i++) {
            for (j=0;j<9;) {
                k=s[i][j];
                r+=k*f[i];
                c+=k*f[j];
                g+=k*f[j++/3+3*(i/3)];
                q+=5*f[k-1];
            }
        }
        return (r==z&&c==z&&g==z&&q==z)?0:1;
    }

那么这是如何工作的呢?我基本上只是创建自己的数字基,并在每个数字中具有足够的分辨率,这样,在通过难题一次之后,只需知道三个数字的比较就可以知道它是否有效。我为这个问题选择了基数49,但是任何大于45的基数都足够。

一个(希望的)清晰的例子:假设数独难题中的每个“行”都是以49为底的数字。为了简单起见,我们将基数49中的每个数字表示为矢量中的基数10中的数字。因此,如果所有行都是“正确的”,我们期望以下以49为底的数字(作为以10为底的向量):

(45,45,45,45,45,45,45,45,45)

或转换为一个以10为底的数字: 1526637748041045

所有列都遵循类似的逻辑,“子网格”遵循相同的逻辑。在最终分析中遇到的任何不等于此“理想数字”的值都表示拼图解决方案无效。

编辑以解决全5s漏洞和其他相关问题:根据每个拼图中每个数字应该有9个的想法,我添加了第四个以49为底的数字。因此,对于每次出现的以10为基数的数字(代表该数字的索引),我在以49为基数的数字中的每个数字加5。例如,如果有10 9和9 8、9 7、8 6和所有其他9个,您将得到一个以49为底的数字(作为大小为10的以10为底的向量来处理溢出):

(1, 1, 45, 45, 40, 45, 45, 45, 45, 45)

与我们的“理想” 49基数相比,这将失败。

我的解决方案利用了这种数学解决方案,从而避免了尽可能多的循环和比较。我只是使用一个long值将每个以49为底的数字存储为以10为底的数字,并使用查找数组在列/行/子网格检查值计算期间获取每个以49为底的数字的“因数”。

由于Java并非设计得简洁,因此在数学构造上要小心是我认为可以构造简洁检查器的唯一方法。

让我知道你的想法。


1
实际上,这也遭受到@ steve-verrill提到的同一漏洞-所有5或总计为45的任何数字集都会“欺骗”求解器。我要修改。我有一个想法如何克服它。
程序员

我在最新更新中解决了此漏洞。现在解决这种情况,以及所有其他类型的情况。基本上,不处理每种以10为基数的数字的“计数”是一个严重的疏忽。我现在直接执行该检查,但是使用相同的数学方法(以49为基数)。
ProgrammerDan

丹,感谢您的致谢。我看到了,想知道为什么没有收到通知,但是我看到你在我的名字上加了一个破折号。这似乎使系统感到困惑。只需省略空间。我将考虑更改我的姓名的显示方式。
Level River

啊哈,这就解释了。感谢@steveverrill-我仍然习惯于stackexchange的工作方式。就是说,您对sum-45原理的简洁利用非常出色。使我的解决方案更长的时间来克服它,但这就是生命!
ProgrammerDan


3

Haskell(Lambdabot),65个字节

k x=and$(all$([1..9]==).sort)<$>[x,transpose x,join$chunksOf 3 x]

2

Perl,193个字节

for(@x=1..9){$i=$_-1;@y=();push@y,$a[$i][$_-1]for@x;@y=sort@y;$r+=@y~~@x;@y=();push@y,$a[3*int($i/3)+$_/3][3*($i%3)+$_%3]for 0..8;@y=sort@y;$r+=@y~~@x}for(@a){@y=sort@$_;$r+=@y~~@x}exit($r!=27)

期望以数组形式输入:

@a=(
    [1,2,3,4,5,6,7,8,9],
    [4,5,6,7,8,9,1,2,3],
    [7,8,9,1,2,3,4,5,6],
    [2,3,1,5,6,4,8,9,7],
    [5,6,4,8,9,7,2,3,1],
    [8,9,7,2,3,1,5,6,4],
    [3,1,2,6,4,5,9,7,8],
    [6,4,5,9,7,8,3,1,2],
    [9,7,8,3,1,2,6,4,5]
);

如果@a是解决方案,则退出代码为0 ,否则1返回。

非高尔夫版本:

@x = (1..9);
for (@x) {
    $i = $_ - 1;
    # columns
    @y = ();
    for (@x) {
        push @y, $a[$i][$_-1];
    }
    @y = sort @y;
    $r += @y ~~ @x;
    # sub arrays
    @y = ();
    for (0..8) {
        push @y, $a[ 3 * int($i / 3) + $_ / 3 ][ 3 * ($i % 3) + $_ % 3 ];
    }
    @y = sort @y;
    $r += @y ~~ @x
}
# rows
for (@a) {
    @y = sort @$_;
    $r += @y ~~ @x
}
exit ($r != 27);

将9行,9列和9个子数组中的每一个放入已排序的数组中,并检查是否与array匹配(1..9)$r对于每个成功的匹配,该数字将递增,对于有效的解决方案,该总数必须总计为27。


2

J 52 54

-.*/,(9=#)@~.@,"2(0 3 16 A.i.4)&|:(4#3)($,)".;._2]0 :0

将其参数粘贴在命令行上,并以)结尾为:

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

如果传递则返回1,否则返回0。

在内部,它将9x9网格转换为3x3x3x3网格,并在轴上进行一些排列以获取最后2个维度中的所需单位(行,线和框)。

之后,检查每个单元具有9个唯一值。

可能还远未达到完美,但已经超过了大多数;-)


乍一看,你已经被抓被一些其他的同样的要求....你的回报应该扭转... 0传中,非零失败
戴维·威尔金斯

0通过是愚蠢的。有一个原因,布尔选择1为true,选择0为false。但是你是对的。添加2个字符。
jpjacobs 2014年

将其视为退出状态,而不是布尔值
David Wilkins 2014年

我选择您的答案是因为它可行。您遵循规则,程序很短。谢谢!
David Wilkins

好吧,我挑剔了……事实上,我不能证明没有选择比您的答案短的Golfscript答案……但是第二名的荣誉
David Wilkins

2

Mathematica,84个 79个字符

f=Tr[Norm[Sort@#-Range@9]&/@Join[#,Thread@#,Flatten/@Join@@#~Partition~{3,3}]]&

例子:

f[{{1,2,3,4,5,6,7,8,9},
   {4,5,6,7,8,9,1,2,3},
   {7,8,9,1,2,3,4,5,6},
   {2,3,1,5,6,4,8,9,7},
   {5,6,4,8,9,7,2,3,1},
   {8,9,7,2,3,1,5,6,4},
   {3,1,2,6,4,5,9,7,8},
   {6,4,5,9,7,8,3,1,2},
   {9,7,8,3,1,2,6,4,5}}]

0

f[{{2,1,3,4,5,6,7,8,9},
   {4,5,6,7,8,9,1,2,3},
   {7,8,9,1,2,3,4,5,6},
   {2,3,1,5,6,4,8,9,7},
   {5,6,4,8,9,7,2,3,1},
   {8,9,7,2,3,1,5,6,4},
   {3,1,2,6,4,5,9,7,8},
   {6,4,5,9,7,8,3,1,2},
   {9,7,8,3,1,2,6,4,5}}]

2

f[{{0,2,3,4,5,6,7,8,9},
   {4,5,6,7,8,9,1,2,3},
   {7,8,9,1,2,3,4,5,6},
   {2,3,1,5,6,4,8,9,7},
   {5,6,4,8,9,7,2,3,1},
   {8,9,7,2,3,1,5,6,4},
   {3,1,2,6,4,5,9,7,8},
   {6,4,5,9,7,8,3,1,2},
   {9,7,8,3,1,2,6,4,5}}]

3


您的第三个输出示例:3总是表明输入无效,或者有时是对失败的解决方案的响应?
David Wilkins 2014年

2

Javascript ES6,150个字符

将输入作为无任何分界符的81个字符的字符串。

s=>s.match("^(?=(#.{0,8}#.{9})+$)(?=(#(.{9}){0,8}#.){9})((#.?.?(.{9}){0,2}#...){3}.{18})+$".replace(/#(.*?)#/g,"123456789".replace(/./g,"(?=$$1$&)")))

函数返回null否定答案,第一个元素中包含原始字符串的数组为肯定值。可以通过添加!!到函数开始更改为bool 。

测试(有关更多详情,请参阅相关挑战):

f=s=>s.match("^(?=(#.{0,8}#.{9})+$)(?=(#(.{9}){0,8}#.){9})((#.?.?(.{9}){0,2}#...){3}.{18})+$".replace(/#(.*?)#/g,"123456789".replace(/./g,"(?=$$1$&)")))
;`123456789456789123789123456231564897564897231897231564312645978645978312978312645
725893461841657392396142758473516829168429537952378146234761985687935214519284673
395412678824376591671589243156928437249735186738641925983164752412857369567293814
679543182158926473432817659567381294914265738283479561345792816896154327721638945
867539142324167859159482736275398614936241587481756923592873461743615298618924375
954217683861453729372968145516832497249675318783149256437581962695324871128796534
271459386435168927986273541518734269769821435342596178194387652657942813823615794
237541896186927345495386721743269158569178432812435679378652914924813567651794283
168279435459863271273415986821354769734692518596781342615947823387526194942138657
863459712415273869279168354526387941947615238138942576781596423354821697692734185
768593142423176859951428736184765923572389614639214587816942375295837461347651298`
.split`
`.every(f)
&&
`519284673725893461841657392396142758473516829168429537952378146234761985687935214
839541267182437659367158924715692843624973518573864192298316475941285736456729381
679543182158926473432817659567381294914256738283479561345792816896154327721638945
867539142324167859159482736275398684936241517481756923592873461743615298618924375
754219683861453729372968145516832497249675318983147256437581962695324871128796534
271459386435168927986273541518734269769828435342596178194387652657942813823615794
237541896186927345378652914743269158569178432812435679495386721924813567651794283
168759432459613278273165984821594763734982516596821347615437829387246195942378651
869887283619214453457338664548525781275424668379969727517385163319223917621449519
894158578962859187461322315913849812241742157275462973384219294849882291119423759
123456789456789123564897231231564897789123456897231564312645978645978312978312645
145278369256389147364197258478512693589623471697431582712845936823956714931764825`
.split`
`.every(s => !f(s))

那是一个荒谬的正则表达式。
ETHproductions 2016年

2

R,63 50字节

假设输入m是9x9的数字矩阵。

all(apply(m,1,match,x=1:9),apply(m,2,match,x=1:9))

我是正确的,进一步打高尔夫球是可能的。

说明:

    apply(m,1,match,x=1:9),

m,并为每行应用该match函数。我们指定了另一个x=1:9要传递给的参数matchx是默认的第一位置参数,因此每一行都位于第二个参数位置,即table。该函数match查找xin的 实例table。那么,在这种情况下,它将1:9在每一行中寻找(数字1到9)。对于每个1:9,它将返回TRUE(或FALSE如果找到(或找不到)该数字)。

因此,这将产生一系列81个布尔值。

                           apply(m,2,match,x=1:9)

对输入的每一列重复以上操作。

all(                                             )

最后,all检查布尔值列表中的每个元素是否为TRUE。当且仅当解决方案正确时(即每个数字),情况才会如此1:9在每一列和每一行中仅出现一次),情况才会如此。

旧方法:

for(i in 1:2)F=F+apply(m,i,function(x)sort(x)==1:9);sum(F)==162

它接受每一行,对其进行排序,然后将其与进行比较[1, 2, ... 9]。正确的行应完全匹配。然后,对每一列都执行相同的操作。总共,我们应该有162个完全匹配项,这是最后一部分要检查的内容。这里可能还有进一步打高尔夫球的空间...


看起来您正在检查列和行,而不是盒子...
JayCe,

1

哈斯克尔-175

import Data.List
c=concat
m=map
q=[1..9]
w=length.c.m (\x->(x\\q)++(q\\x))
b x=c.m(take 3.drop(3*mod x 3)).take 3.drop(3*div x 3)
v i=sum$m(w)[i,transpose i,[b x i|x<-[0..8]]]

该函数v是要调用的函数。它通过获取列表中每一行,每一列和每一块的差异[1..9]并汇总这些差异列表的长度来工作。

使用示例数独进行演示:

*Main> :l so-22443.hs 
[1 of 1] Compiling Main             ( so-22443.hs, interpreted )
Ok, modules loaded: Main.
*Main> v [[1,2,3,4,5,6,7,8,9],[4,5,6,7,8,9,1,2,3],[7,8,9,1,2,3,4,5,6],[2,3,1,5,6,4,8,9,7],[5,6,4,8,9,7,2,3,1],[8,9,7,2,3,1,5,6,4],[3,1,2,6,4,5,9,7,8],[6,4,5,9,7,8,3,1,2],[9,7,8,3,1,2,6,4,5]]
0

1

Javascript-149个字符

r=[];c=[];g=[];for(i=9;i;)r[o=--i]=c[i]=g[i]=36;for(x in a)for(y in z=a[x]){r[v=z[y]-1]-=y;c[v]-=x;g[v]-=3*(x/3|0)+y/3|0}for(i in r)o|=r[i]|c[i]|g[i]

期望a存在一个数组,并o为输出创建一个变量,该变量0成功执行,否则返回非零值。

通过检查每个行,列和3 * 3网格的每个值出现的位置的总和等于36(0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8)来工作。

测试中

a=[
    [1,2,3, 4,5,6, 7,8,9],
    [4,5,6, 7,8,9, 1,2,3],
    [7,8,9, 1,2,3, 4,5,6],

    [2,3,1, 5,6,4, 8,9,7],
    [5,6,4, 8,9,7, 2,3,1],
    [8,9,7, 2,3,1, 5,6,4],

    [3,1,2, 6,4,5, 9,7,8],
    [6,4,5, 9,7,8, 3,1,2],
    [9,7,8, 3,1,2, 6,4,5]
  ];

给出'o = 0'

a=[
    [1,2,3, 4,5,6, 7,8,9],
    [4,5,6, 7,8,9, 1,2,3],
    [7,8,9, 1,2,3, 4,5,6],

    [2,3,1, 5,6,4, 8,9,7],
    [5,6,4, 8,9,7, 2,3,1],
    [8,9,7, 2,3,1, 5,6,4],

    [3,1,2, 6,4,5, 9,7,8],
    [6,4,5, 9,7,8, 3,1,2],
    [9,7,8, 3,1,2, 6,5,4]
  ];

(最后2位数字已交换)

o=-1

a=[
    [5,5,5, 5,5,5, 5,5,5],
    [5,5,5, 5,5,5, 5,5,5],
    [5,5,5, 5,5,5, 5,5,5],

    [5,5,5, 5,5,5, 5,5,5],
    [5,5,5, 5,5,5, 5,5,5],
    [5,5,5, 5,5,5, 5,5,5],

    [5,5,5, 5,5,5, 5,5,5],
    [5,5,5, 5,5,5, 5,5,5],
    [5,5,5, 5,5,5, 5,5,5]
  ];

o=-284


1

Haskell中,121个 130 127字节(87 Lambdabot)

import Data.List
import Data.List.Split
c=concat
t=transpose
k=chunksOf
p x=all(==[1..9])$(sort<$>)=<<[x,t x,k 9.c.c.t$k 3<$>x]

用途:

-- k 9.c.c.t$k 3<$> x = chunksOf 9 $ concat $ concat $ transpose $ map chunksOf 3 x

let ts = k 9$[10*a+b|a<-[1..9],b<-[1..9]] --yep, this is ugly
in k 9.c.c.t$k 3<$>ts
-- prints:
--[[11,12,13,21,22,23,31,32,33],[41,42,43,51,52,53,61,62,63],[71,72,73,81,82,83,91,92,93],[14,15,16,24,25,26,34,35,36],[44,45,46,54,55,56,64,65,66],[74,75,76,84,85,86,94,95,96],[17,18,19,27,28,29,37,38,39],[47,48,49,57,58,59,67,68,69],[77,78,79,87,88,89,97,98,99]]

Lambdabot默认情况下会加载Data.List和Data.List.Split(我不认为BlackCap的解决方案会选中这些框)。

欢迎提出改进意见

//编辑:我搞砸了:)
//编辑:BlackCap保存了3个字节


你说得对,我没有注意到,检查的行和列是不够的..

好吧,我也搞砸了:)
michi7x7 '16

1
您可以替换(map sort)(sort<$>)
BlackCap,2016年

1
.c$(sort<$>)<$>$(sort<$>)=<<

哦,我的,应该记得那些2
michi7x7


0

Clojure,151个字节

相当长,但其他人似乎也是如此。同样令人烦恼的是,集合的联合需要一个require,所以我改用了向量的连接。

遍历每一行和每一列,如果该值在1到9之间,它将发出三个向量,一个向量用于行,列和3x3单元。成功返回0,nil否则返回两个额外的字符,失败则返回1。通过返回来处理1-9以外的数字,nil但会在其他异常(例如非整数值)上崩溃。商为0-2,因此可以安全地使用值89区分单元格值与行和列。

(fn[s](if(= 243(count(set(apply concat(for[i(range 9)j(range 9)](let[v(nth(nth s i)j)q #(quot % 3)](if(<= 1 v 9)[[8 v i][9 v j][(q i)(q j)v]])))))))0))

输入是向量的嵌套向量(这样可以nth工作):

(def sudoku [[1 2 3 4 5 6 7 8 9]
             [4 5 6 7 8 9 1 2 3] 
             [7 8 9 1 2 3 4 5 6] 
             [2 3 1 5 6 4 8 9 7] 
             [5 6 4 8 9 7 2 3 1] 
             [8 9 7 2 3 1 5 6 4] 
             [3 1 2 6 4 5 9 7 8] 
             [6 4 5 9 7 8 3 1 2] 
             [9 7 8 3 1 2 6 4 5]])

取消高尔夫:

(defn f [s]
  (->> (for [i (range 9) j (range 9)]
         (let [v (-> s (nth i) (nth j)) q #(quot % 3)]
           (if (<= 1 v 9)
             [[:row v i] [:col v j] [:cell [(q i) (q j)] v]])))
    (apply concat)
    set
    count
    (#(if (= 243 %) :pass :fail))))

0

PHP,196190字节

while($i<9){for($b=$c=$k=$y="";$y++<9;)$b.=($a=$argv)[$y][$i];for(;$k<3;)$c.=substr($a[++$k+$i-$i%3],$i%3*3,3);if(($u=count_chars)($a[++$i],3)<($d=123456789)|$u($b,3)<$d|$u($c,3)<$d)die(1);}

程序采用9个单独的命令行参数(网格的每一行一个数字字符串);
退出1(错误)表示无效,0(确定)表示有效。

用运行php -nr '<code>' <row1> <row2> ...

分解

while($i<9)
{
    for($b=$c=$k=$y="";$y++<9;)$b.=($a=$argv)[$y][$i];  // column to string
    for(;$k++<3;)$c.=substr($a[$i-$i%3+$k],$i%3*3,3);   // sub-grid to string
    if(($u=count_chars)($a[++$i],3)<($d=123456789)      // check row
        |$u($b,3)<$d                                    // check column
        |$u($c,3)<$d                                    // check sub-grid
    )die(1);                                            // test failed: exit with 1
}

说明

count_chars计算字符串中的字符,通常创建一个以ascii码作为键,并将字符计数作为值的数组;但随着3作为模式参数,它将根据字符创建一个排序的字符串;可以轻松地将其与带有所需数字的数字进行比较。

比较不仅检查重复项,还包括检查无效字符。它只需要<,而不是!=,因为这是数字比较:PHP会尽可能地将字符串解释为数字。123e567890x3456789或类似字符无法显示,因为字符已排序;当然,任何缺少数字的纯整数都比123456789... 小.23456789

$a=$argv保存一个字节,$d=123456789保存九个字节并$u=count_chars保存13。


-1

C# - 306个 298 288字符

以下控制台程序用于调用检查功能;

static void Main(string[] args)
    {
        int[,] i={{1,2,3,4,5,6,7,8,9},
             {4,5,6,7,8,9,1,2,3},
             {7,8,9,1,2,3,4,5,6},
             {2,3,1,5,6,4,8,9,7},
             {5,6,4,8,9,7,2,3,1},
             {8,9,7,2,3,1,5,6,4},
             {3,1,2,6,4,5,9,7,8},
             {6,4,5,9,7,8,3,1,2},
             {9,7,8,3,1,2,6,4,5}
            };

            Console.Write(P(i).ToString());
    }

所有这些操作就是初始化数组并将其传递给检查函数P。

检查功能如下(高尔夫形式);

private static int P(int[,]i){int[]r=new int[9],c=new int[9],g=new int[9];for(int p=0;p<9;p++){r[p]=45;c[p]=45;g[p]=45;}for(int y=0;y<9;y++){for(int x=0;x<9;x++){r[y]-=i[x,y];c[x]-=i[x,y];int k=(x/3)+((y/3)*3);g[k]-=i[x,y];}}for(int p=0;p<9;p++)if(r[p]>0|c[p]>0|g[p]>0)return 1;return 0;}

或以完全布局的形式;

    private static int P(int[,] i)
    {
        int[] r = new int[9],c = new int[9],g = new int[9];
        for (int p = 0; p < 9; p++)
        {
            r[p] = 45;
            c[p] = 45;
            g[p] = 45;
        }

        for (int y = 0; y < 9; y++)
        {
            for (int x = 0; x < 9; x++)
            {
                r[y] -= i[x, y];

                c[x] -= i[x, y];

                int k = (x / 3) + ((y / 3) * 3);
                g[k] -= i[x, y];
            }
        }

        for (int p = 0; p < 9; p++)
            if (r[p] > 0 | c[p] > 0 | g[p] > 0) return 1;

        return 0;
    }

这使用了所有列,行和子网格的总和应为45的想法。它通过输入数组工作,并从其行,列和子网格中减去每个位置的值。完成后,它会检查所有行,列或子网格是否仍然没有值。

如果数组是有效的Sudoku解决方案,则按要求返回0,否则返回非零(1)。


我认为您可以使用private static int P(int[,]i){int[]r=new int[9],c=new int[9],g=new int[9];来节省一些字符。(请注意,在方括号后要除去空格]。)此外,我不确定,但我认为您可能会摆脱private static
user12205 2014年

另外,对于最后一部分,我们可以在C语言中删除一些花括号for(int p=0;p<9;p++)if(r[p]>0|c[p]>0|g[p]>0)return 1;return 0;},例如,虽然不确定在C#中是否可以使用。(我实际上不知道C#)
2014年

@ace-根据您的建议,我进行了一些增强。现在降至298个字符。
2014年

根据@ace的评论,再修剪了10个字符。
2014年

1
充满5的数组会发生什么?所有的行,列和广场加起来45
级圣河
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.