Code Golf:单词搜索解算器

时间:2010-04-02 17:24:49

标签: string language-agnostic code-golf rosetta-stone

注意:这是我的第一个Code Golf挑战/问题,所以我可能没有使用下面正确的格式。我不确定如何标记这个特定的问题,这应该是社区维基吗?谢谢!

此Code Golf挑战是关于解决单词搜索的问题!

维基百科定义的单词搜索是:

  

单词搜索,单词查找,单词搜索,   单词侦探或神秘词拼图是   一个文字游戏,是一个单词的字母   在网格中,通常有一个   矩形或方形。该   这个难题的目标是找到   并标记隐藏在里面的所有单词   盒子。这些话可能是   水平,垂直或   斜。通常是隐藏的列表   提供了单词,但更多   具有挑战性的谜题可能让玩家   搞清楚。很多单词搜索   谜题有一个主题,所有的   隐藏的词是相关的。

搜索此挑战的单词将全部为矩形网格,其中包含要提供的单词列表。这些单词可以写成垂直,水平或对角


输入/输出

用户输入他们的单词搜索,然后输入要在他们的网格中找到的单词。这两个输入传递给您将要编写的函数。由您决定如何声明和处理这些对象。

使用下面描述的策略或您自己的策略,该函数在搜索中找到特定的单词并输出其起始坐标(简单的行号和列号)和结束坐标。如果您发现该单词出现两次,则必须输出两组坐标。如果这个单词是回文,你可以任意选择一个结尾作为单词的“开头”。


实施例

输入:

A I Y R J J Y T A S V Q T Z E 
X B X G R Z P W V T B K U F O 
E A F L V F J J I A G B A J K 
R E S U R E P U S C Y R S Y K 
F B B Q Y T K O I K H E W G N 
G L W Z F R F H L O R W A R E 
J A O S F U E H Q V L O A Z B 
J F B G I F Q X E E A L W A C 
F W K Z E U U R Z R T N P L D 
F L M P H D F W H F E C G W Z 
B J S V O A O Y D L M S T C R 
B E S J U V T C S O O X P F F 
R J T L C V W R N W L Q U F I 
B L T O O S Q V K R O W G N D 
B C D E J Y E L W X J D F X M 

要查找的字词:codegolf

输出:

row 12, column 8 --> row 5, column 1

策略

以下是您可能会考虑使用的一些策略。完全取决于您决定要使用的策略;它不必在此列表中。

  • 寻找这个词的第一个字母;在每次出现时,查看周围的八个字母,看看这个单词的下一个字母是否存在。
  • 与上述相同,只是查找并排有两个相同字母的单词的一部分。
  • 计算整个网格中每个字母的出现频率,然后从您必须找到的单词中选择一个最少出现的字母并搜索该字母。在每次出现这封信时,你会看到它周围的八个字母,看看这个字的下一个和前一个字母是否存在。

7 个答案:

答案 0 :(得分:12)

Python - 186个字符

def f(g,W):w=g.find("\n")+1;L=len(W);print" --> ".join("row %s, column %s"%(x/w+1
,x%w+1)for i in range(len(g))for j in(-w-1,-w,-w+1,-1,1,w-1,w,w+1)for x in(i,i+(L
-1)*j)if g[i::j][:L]==W)

测试代码:

grid="""A I Y R J J Y T A S V Q T Z E 
X B X G R Z P W V T B K U F O 
E A F L V F J J I A G B A J K 
R E S U R E P U S C Y R S Y K 
F B B Q Y T K O I K H E W G N 
G L W Z F R F H L O R W A R E 
J A O S F U E H Q V L O A Z B 
J F B G I F Q X E E A L W A C 
F W K Z E U U R Z R T N P L D 
F L M P H D F W H F E C G W Z 
B J S V O A O Y D L M S T C R 
B E S J U V T C S O O X P F F 
R J T L C V W R N W L Q U F I 
B L T O O S Q V K R O W G N D 
B C D E J Y E L W X J D F X M """.lower().replace(" ","")
f(grid,"codegolf")
f(grid,"serverfault")
f(grid,"superuser")

此版本为196个字符并接受网格而不进行任何额外调整

def f(g,W):w=g.find("\n")+1;L=len(W);print" --> ".join("row %s, column %s"%(x/w+1,x%w/2+1)for i in range(len(g))for j in(-w-2,-w,-w+2,-2,2,w-2,w,w+2)for x in(i,i+(L-1)*j)if g[i::j][:L].lower()==W)

测试代码:

grid="""A I Y R J J Y T A S V Q T Z E 
X B X G R Z P W V T B K U F O 
E A F L V F J J I A G B A J K 
R E S U R E P U S C Y R S Y K 
F B B Q Y T K O I K H E W G N 
G L W Z F R F H L O R W A R E 
J A O S F U E H Q V L O A Z B 
J F B G I F Q X E E A L W A C 
F W K Z E U U R Z R T N P L D 
F L M P H D F W H F E C G W Z 
B J S V O A O Y D L M S T C R 
B E S J U V T C S O O X P F F 
R J T L C V W R N W L Q U F I 
B L T O O S Q V K R O W G N D 
B C D E J Y E L W X J D F X M """
f(grid,"codegolf")
f(grid,"serverfault")
f(grid,"superuser")

答案 1 :(得分:8)

Perl,226 char

sub h($){"row ",$%=1+($x=pop)/$W,", column ",1+$x%$W}
@S=map/[^ ]/g,<STDIN>;
B:for(@ARGV){
 for$d(map{$_,-$_}1,$W=@S/$.,$W-1,$W+1){
  A:for$s(0..$#S){
   $t=$s-$d;for(/./g){next A if$S[$t+=$d]ne$_||$t<0}
   print h$s,' --> ',h$t,$/;
   next B
}}}

字符数不包括换行符和缩进词,其中包含可读性。 我假设字母矩阵用标准输入指定,目标字是命令行参数。

第一行(在sub h定义之后)将所有非空格字符映射到单个数组@S。然后迭代所有目标词,在可能出现的方向上($W是拼图的宽度),以及当前目标词中的所有字母,直到找到匹配为止。

$ perl wordsearch.pl CODEGOLF RACECAR BYKLHQU <<EOF
A I Y R J J Y T A S V Q T Z E 
X B X G R Z P W V T B K U F O 
E A F L V F J J I A G B A J K 
R E S U R E P U S C Y R S Y K 
F B B Q Y T K O I K H E W G N 
G L W Z F R F H L O R W A R E 
J A O S F U E H Q V L O A Z B 
J F B G I F Q X E E A L W A C 
F W K Z E U U R Z R T R A C E 
C A R P H D F W H F E C G W Z 
B J S V O A O Y D L M S T C R 
B E S J U V T C S O O X P F F 
R J T L C V W R N W L Q U F I 
B L R A C E C A R R O W G N D 
B C D E J Y E L W X J D F X M 
EOF
row 12, column 8 --> row 5, column 1
row 14, column 3 --> row 14, column 9
row 3, column 12 --> row 9, column 6

答案 2 :(得分:6)

Perl - 243

(不包括换行符,所有这些都是可选的)

可以找到大部分去高尔夫的代码here

$/="";@w=split//,pop;($b=<>)=~y/ //d;$W=1+index$b,"\n";
for(1,2){for(0,$W-2..$W){$p=join"."x$_,@w;
push@m,[$-[0],$+[0]-1]while$b=~/$p/sg}
@w=reverse@w;@m=map[reverse@$_],@m}
$t="row %d, column %d";
printf"$t --> $t\n",map{1+$_/$W,1+$_%$W}@$_ for@m;

用法:作为脚本运行。可以wordsearch.pl boardfile searchword从文件中读取,也可以wordsearch.pl searchword从STDIN读取电路板(嘿,popshift短两个字符!)

我们的想法是我们将棋盘读成一个字符串(丢掉字母之间的额外空格),并记下它的宽度(通过计算字符直到第一个换行符)。然后我们使用s正则表达式修饰符进行一系列正则表达式匹配以查找单词,以允许匹配跨越行。如果一个4字母宽的棋盘(所以每行5个字符包括换行符)和搜索词“CAR”,我们可以使模式/CAR/匹配向前,/C...A...R/以匹配向西南方向, /C....A....R/匹配向下,/C.....A.....R/匹配向东南方向匹配。对于每场比赛,我们记录比赛的开始和结束位置。

然后我们反转搜索词(“CAR” - >“RAC”)并再次执行,这样我们就可以匹配左,上,西北和东北的单词。当然,我们希望确保交换开始/结束位置。为了保存代码,我将匹配位置交换两次;前进单词的匹配被交换两次(因此它们是未交换的),而后向单词的匹配只交换一次,所以它们将被交换掉。

最后,只需将匹配偏移量转换为电路板字符串并将其转换为行/列对,并将输出格式化为问题所需的格式。

答案 3 :(得分:4)

AWK - 252 255

NF<2{l=split($1,w,"")}NF>1{for(i=1;i<=NF;)t[x=i++,y=NR]=$i}END{
for(i=1;i<=x;++i)for(j=0;++j<=y;)for(a=0;a<9;++a)if(t[I=i,J=j]==w[1])
for(k=1;k<l;){if(!(T=t[I+=int(a/3)-1,J+=a%3-1])||T!=w[++k])break;if(k==l)
print"row "j (B=", column ")i" --> row "J B I}}

输入应采用

格式
....
B L T O O S Q V K R O W G N D 
B C D E J Y E L W X J D F X M 
CODEGOLF

答案 4 :(得分:3)

C ++ C, 411 400 388 367个字符

我第一次尝试打高尔夫球。

#include<stdio.h>
main(){char m[999],w[99];int r,c,l=-1,x=-1,y=-1,i=0,j,k;scanf("%s %d %d"
,w,&r,&c);for(;w[l+1];++l);for(;i<r*c;scanf("%s",&m[i++]));for(;y<2;++y)
for(;x<2;++x)if(x|y)for(i=(y<0)*l;i<r-(y>0)*l;++i)for(j=(x<0)*l;j<c-(x>0
)*l;++j)for(k=0;k<=l&&w[k++]==m[(i+k*y)*c+j+k*x];)k>l?printf(
"row %i, column %i --> row %i, column %i\n",i+1,j+1,i+y*l+1,j+x*l+1):0;}

它在没有警告的情况下编译而没有额外的标志。

这是带有空格的版本:

#include<stdio.h>
main() {
    char m[999], w[99];
    int r, c, l = -1, x = -1, y = -1, i = 0, j, k;

    scanf("%s %d %d", w, &r, &c);
    for (; w[l+1]; ++l);
    for (; i < r*c; scanf("%s", &m[i++]));
    for (; y < 2; ++y)
        for (; x < 2; ++x)
            if (x | y)
                for (i = (y<0) * l; i < r - (y>0) * l; ++i)
                    for (j = (x<0) * l; j < c - (x>0) * l; ++j)
                        for (k = 0; k <= l && w[k++] == m[(i+k*y) * c + j+k*x];)
                            k > l ? printf("row %i, column %i --> row %i, column %i\n",
                                    i + 1, j + 1, i + y*l + 1, j + x*l + 1)
                                  : 0;
}

stdin上的预期输入如下:

CODEGOLF 15 15
A I Y R J J Y T A S V Q T Z E
X B X G R Z P W V T B K U F O
...

其中15 15分别是行数和列数。

由于这是我的第一轮高尔夫,我可以在网上找到一些奇怪的常用技巧,我会列出一些我发现的:

  • 尝试将循环体保存到单个语句中以保存胡须(2个字符) 示例:使用逗号运算符的任何内容。

  • 可以使用条件表达式(?:)代替if(1个字符)。
    示例:代替if(x)printf("");,写下x?printf(""):0;。这有效,因为printf会返回int

  • 当用作0(?字符)时,使用布尔值为1int的事实。
    示例:代替(y>0?r-l:r),写下r-(y>0)*l。这里的节省在括号中,在这种情况下是必要的。

  • while循环永远不会比for循环短,并且大部分时间都会更长(&gt; = 0个字符)。
    示例while(x)y;for(;x;y);一样长,但for;一样,您也可以使用循环体,而无需支付额外费用{{1} }}。

  • 将循环增量放入使用循环计数器的最后一个表达式(1个字符) 示例:代替for(;x<b;++x)printf("%i",x);,写下for(;x<b;)printf("%i",x++);

  • 不要使用main的返回类型(4个字符)。

  • 不要main的{​​{1}}声明(9个字符)。

  • 尽可能使用return&代替|&&(1个字符)。
    示例:代替||,写下if(x||y)。这仅在您不依赖if(x|y)&&的短路行为时才有效。

  • 内联||功能并删除strlen(11个字符)。

如果您不关心编译器警告:

  • 不要包含任何标题(许多字符)。

答案 5 :(得分:3)

Python,318笔。

from itertools import*
f=lambda x,y,i,j,n:(x-i+1,y-j+1)*(not n)or all((2*i+j,x+1,y+1,x<c,y<d))and a[x][y*2]==n[0]and f(x+i,y+j,i,j,n[1:])
w=raw_input
a=list(iter(w,''))
c=len(a)
d=len(a[0])/2
r=range
z=r(-1,2)
s='row %d, column %d'
for x in product(r(c),r(d),z,z,[w()]):
 if f(*x):print s%(x[0]+1,x[1]+1),'-->',s%f(*x)

<小时/> 样本输入:

A I Y R J J Y T A S V Q T Z E 
X C O D E G O L F B K U F O Z
E A F L V F J J I A G B A J K 
R E S U R E P U S C Y R S Y K 
F B B Q Y T K O I K H E W G N 
G L W Z F R F H L O R W A R E 
J A O S F U E H Q V L O A Z B 
J F B G I F Q X E E A L W A C 
F W K Z E U U R Z R T N P L D 
F L M P H D F W H F E C G W Z 
B J S V O A O Y D L M S T C R 
B E S J U V T C S O O X P F F 
R J T L C V W R N W L Q U F I 
B L T O O S Q V K R O W G N D 
B C D E J Y E L W X J D F X M 

CODEGOLF

输出:

$ python wordsearch < wordsearchinput.txt
row 2, column 2 --> row 2, column 9
row 12, column 8 --> row 5, column 1

根据“编辑 - 回答 - 而不是评论 - 如何我应该修复此许可证”发布。

答案 6 :(得分:0)

Python: 491 - 353个字符

我猜还有一些改进空间,所有评论都欢迎。

策略:查找第一个字母的所有出现,然后尝试在所有方向上获取该单词。

import sys;r=range(-1,2);k=''.join;q="row %s, column %s"
a=[l[:-1:2]for l in sys.stdin]
b=sys.argv[1];c=len(a[0])
for x,y in[(x/c,x%c)for x,h in enumerate(k(map(k,a)))]:
 for i,j in[(i,j)for i in r for j in r if i or j<>0]:
  if k([a[x+z*i][y+z*j]for z in range(len(b))if 0<=x+z*i<c and 0<=y+z*j<len(a)])==b:print q%(x+1,y+1)+" --> "+q%(x+z*i+1,y+z*j+1)

使用示例:

  

cat input.txt | python test.py CODEGOLF

示例输出:

  

第12行,第8列 - &gt;第5行第1列