Code Golf:验证Sudoku Grid

时间:2010-12-10 08:33:12

标签: algorithm code-golf sudoku

简介

有效的数独网格填充数字1到9,在9,行或列的每个子块中没有数字出现多次。如果您不熟悉这个流行的谜题,请阅读this article以获取更多详细信息。

挑战

挑战在于编写最短的程序来验证可能未满的Sudoku网格。

输入将是一行9行,每行9个字符,代表网格。空单元格将由.表示。如果网格有效,则输出应为Valid,否则输出Invalid

实施例

输入

123...789
...456...
456...123
789...456
...123...
564...897
...231...
897...564
...564...

输出

Valid

输入

123456789
987654321
123456789
123456789
987654321
123456789
123456789
987654321
123456789

输出

Invalid

Code Golf Rules

请以解决此问题的任何语言发布您的最短代码。输入和输出可以通过stdin和stdout或您选择的其他文件来处理。

Winner将是在发布此问题之前存在实现的语言中最短的解决方案(按字节数)。因此,虽然您可以自由地使用您刚刚编写的语言来提交0字节的解决方案,但它不会计算,并且您可能会得到一些支持。

14 个答案:

答案 0 :(得分:11)

Golfscript:56

n%{zip''+9/.{'.'-..&=}%$0=\}:|2*{3/}%|;**"InvV"3/="alid"

答案 1 :(得分:9)

C: 165 162 161 160 159

int v[1566],x,y=9,c,b;main(){while(y--)for(x=9;x--+1;)if((c
=getchar()*27)>1242)b|=v[x+c]++|v[y+9+c]++|v[x-x%3+y/3+18+c]
++;puts(b?"Invalid":"Valid");return 0;}

不需要两个换行符。由josefx保存的一个字符:-) ...

答案 2 :(得分:6)

Haskell: 207 230 218 195 172

import List
t=take 3
h=[t,t.drop 3,drop 6]
v[]="V"
v _="Inv"
f s=v[1|v<-[s,transpose s,[g=<<f s|f<-h,g<-h]],g<-map(filter(/='.'))v,g/=nub g]++"alid\n"
main=interact$f.lines

答案 3 :(得分:5)

Perl: 168 128

$_=join'',<>;@a=/.../g;print+(/(\d)([^\n]{0,8}|(.{10})*.{9})\1/s
+map"@a[$_,$_+3,$_+6]"=~/(\d).*\1/,0..2,9..11,18..20)?Inv:V,alid

第一个正则表达式检查同一行和列中的重复项;第二个正则表达式处理“相同框”中的重复。

通过将第一个正则表达式中的\n替换为文字换行符(1个字符)或使用&gt; = Perl 5.12,将[^\n]替换为\N(3),可以进一步改进炭)

早些时候,168 char解决方案: 输入来自stdin,输出是 stderr ,因为它使事情变得如此简单。换行是可选的,不计算在内。

$_=join'',<>;$m=alid.$/;$n=Inv.$m;/(\d)(\N{0,8}|(.{10})*.{9})\1/s&&
die$n;@a=/.../g;for$i(0,8,17){for$j($i..$i+2){
$_=$a[$j].$a[$j+3].$a[$j+6];/(\d).*\1/&&die$n}}die"V$m"

答案 4 :(得分:4)

Python: 230 221 200 185

首先是len = 199的可读版本:

import sys
r=range(9)
g=[raw_input()for _ in r]
s=[[]for _ in r*3]
for i in r:
 for j in r:
  n=g[i][j]
  for x in i,9+j,18+i/3*3+j/3:
<T>if n in s[x]:sys.exit('Invalid')
<T>if n>'.':s[x]+=n
print'Valid'

由于SO不显示制表符,我使用<T>来表示单个制表符。

PS。同样的方法minEvilized低至185个字符:

r=range(9)
g=[raw_input()for _ in r]
s=['']*27
for i in r:
 for j in r:
    for x in i,9+j,18+i/3*3+j/3:n=g[i][j];s[x]+=n[:n>'.']
print['V','Inv'][any(len(e)>len(set(e))for e in s)]+'alid'

答案 5 :(得分:4)

Perl,153 char

@B包含董事会的81个要素。

&E测试@B的子集是否包含任何重复数字

主循环验证每个列,“块”和拼图的行

sub E{$V+="@B[@_]"=~/(\d).*\1/}
@B=map/\S/g,<>;
for$d(@b=0..80){
E grep$d==$_%9,@b;
E grep$d==int(($_%9)/3)+3*int$_/27,@b;
E$d*9..$d*9+8}
print$V?Inv:V,alid,$/

答案 6 :(得分:3)

Python: 159 158

v=[0]*244
for y in range(9):
 for x,c in enumerate(raw_input()):
  if c>".":
<T>for k in x,y+9,x-x%3+y//3+18:v[k*9+int(c)]+=1
print["Inv","V"][max(v)<2]+"alid"

&LT; T&GT;是单个制表符

答案 7 :(得分:3)

Common Lisp: 266 252

(princ(let((v(make-hash-table))(r "Valid"))(dotimes(y 9)(dotimes(x
10)(let((c(read-char)))(when(>(char-code c)46)(dolist(k(list x(+ 9
y)(+ 18(floor(/ y 3))(- x(mod x 3)))))(when(>(incf(gethash(+(* k
9)(char-code c)-49)v 0))1)(setf r "Invalid")))))))r))

答案 8 :(得分:2)

Perl:186

输入来自stdin,输出到stdout,输入中的换行符可选。

@y=map/\S/g,<>;
sub c{(join'',map$y[$_],@$h)=~/(\d).*\1/|c(@_)if$h=pop}
print(('V','Inv')[c map{$x=$_;[$_*9..$_*9+8],[grep$_%9==$x,0..80],[map$_+3*$b[$x],@b=grep$_%9<3,0..20]}0..8],'alid')

(为“清晰度”添加了换行符。)

c()是一个函数,它根据作为参数传递的位置编号列表来检查@y中的输入。如果所有位置列表都有效(不包含多于一次的数字),则返回0,否则返回1,使用递归检查每个列表。底线构建此列表列表,将其传递给c()并使用结果选择要输出的正确前缀。

我非常喜欢的一点是,此解决方案利用了@b中“块”位置列表中的“自相似性”(多次重复冗余以避免@b=...进入@b一个单独的陈述):通过将# Grab input into an array of individual characters, discarding whitespace @y = map /\S/g, <>; # Takes a list of position lists. # Returns 0 if all position lists are valid, 1 otherwise. sub c { # Pop the last list into $h, extract the characters at these positions with # map, and check the result for multiple occurences of # any digit using a regex. Note | behaves like || here but is shorter ;) # If the match fails, try again with the remaining list of position lists. # Because Perl returns the last expression evaluated, if we are at the # end of the list, the pop will return undef, and this will be passed back # which is what we want as it evaluates to false. (join '', map $y[$_], @$h) =~ /(\d).*\1/ | c(@_) if $h = pop } # Make a list of position lists with map and pass it to c(). print(('V','Inv')[c map { $x=$_; # Save the outer "loop" variable [$_*9..$_*9+8], # Columns [grep$_%9==$x,0..80], # Rows [map$_+3*$b[$x],@b=grep$_%9<3,0..20] # Blocks } 0..8], # Generates 1 column, row and block each time 'alid') 中的第i个元素乘以3,可以找到整个拼图中第i个块的左上角位置。

更多分散:

{{1}}

答案 9 :(得分:1)

Perl:202

我正在阅读Modern Perl,感觉就像在编写一些东西......(顺便说一下这本书非常酷):

while(<>){$i++;$j=0;for$s(split//){$j++;$l{$i}{$s}++;$c{$j}{$s}++;
$q{(int(($i+2)/3)-1)*3+int(($j+2)/3)}{$s}++}}
$e=V;for$i(1..9){for(1..9){$e=Inv if$l{$i}{$_}>1or$c{$i}{$_}>1or$q{$i}{$_}>1}}
print $e.alid

Count排除不必要的换行符。 这可能需要Perl 5.12.2。

更具可读性:

#use feature qw(say);
#use JSON;

#$json = JSON->new->allow_nonref;

while(<>)
{
    $i++;
    $j=0;
    for $s (split //)
    {
        $j++;
        $l{$i}{$s}++;
        $c{$j}{$s}++;
        $q{(int(($i+2)/3)-1)*3+int(($j+2)/3)}{$s}++;
    }
}

#say "lines: ", $json->pretty->encode( \%l );
#say "columns: ", $json->pretty->encode( \%c );
#say "squares: ", $json->pretty->encode( \%q );

$e = V;
for $i (1..9)
{
    for (1..9)
    {
        #say "checking {$i}{$_}: " . $l{$i}{$_} . " / " . $c{$i}{$_} . " / " . $q{$i}{$_};
        $e = Inv if $l{$i}{$_} > 1 or $c{$i}{$_} > 1 or $q{$i}{$_} > 1;
    }
}

print $e.alid;

答案 10 :(得分:1)

Ruby - 176

f=->x{x.any?{|i|(i-[?.]).uniq!}}
a=[*$<].map{|i|i.scan /./}
puts f[a]||f[a.transpose]||f[a.each_slice(3).flat_map{|b|b.transpose.each_slice(3).map &:flatten}]?'Invalid':'Valid'

答案 11 :(得分:1)

Lua,341字节

虽然我知道Lua不是最好的高尔夫语言,但考虑到它的大小,我认为值得张贴它;)。 非高尔夫,评论和错误打印版本,为了额外的乐趣:)

i=io.read("*a"):gsub("\n","")   -- Get input, and strip newlines
a={{},{},{}} -- checking array, 1=row, 2=columns, 3=squares
for k=1,3 do for l=1,9 do a[k][l]={0,0,0,0,0,0,0,0,0}end end -- fillup array with 0's (just to have non-nils)

for k=1,81 do -- loop over all numbers
    n=tonumber(i:sub(k,k):match'%d') -- get current character, check if it's a digit, and convert to a number
    if n then
        r={math.floor((k-1)/9)+1,(k-1)%9+1} -- Get row and column number
        r[3]=math.floor((r[1]-1)/3)+3*math.floor((r[2]-1)/3)+1 -- Get square number
        for l=1,3 do v=a[l][r[l]] -- 1 = row, 2 = column, 3 = square
            if v[n] then -- not yet eliminated in this row/column/square
                v[n]=nil    
            else
                print("Double "..n.." in "..({"row","column","square"}) [l].." "..r[l]) --error reporting, just for the extra credit :)
                q=1 -- Flag indicating invalidity
            end
        end
    end
end
io.write(q and"In"or"","Valid\n")

高尔夫版本,341字节

f=math.floor p=io.write i=io.read("*a"):gsub("\n","")a={{},{},{}}for k=1,3 do for l=1,9 do a[k][l]={0,0,0,0,0,0,0,0,0}end end for k=1,81 do n=tonumber(i:sub(k,k):match'%d')if n then r={f((k-1)/9)+1,(k-1)%9+1}r[3]=f((r[1]-1)/3)+1+3*f((r[2]-1)/3)for l=1,3 do v=a[l][r[l]]if v[n]then v[n]=nil else q=1 end end end end p(q and"In"or"","Valid\n")

答案 12 :(得分:1)

Python:140

v=[(k,c) for y in range(9) for x,c in enumerate(raw_input()) for k in x,y+9,(x/3,y/3) if c>'.']
print["V","Inv"][len(v)>len(set(v))]+"alid"

答案 13 :(得分:1)

ASL:108

args1["\n"x2I3*x;{;{:=T(T'{:i~{^0}?})}}
{;{;{{,0:e}:;{0:^},u eq}}/`/=}:-C
dc C@;{:|}C&{"Valid"}{"Invalid"}?P

ASL是我制作的Golfscript灵感脚本语言。