注意:这是我的第一个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
以下是您可能会考虑使用的一些策略。完全取决于您决定要使用的策略;它不必在此列表中。
答案 0 :(得分:12)
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)
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)
(不包括换行符,所有这些都是可选的)
可以找到大部分去高尔夫的代码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读取电路板(嘿,pop
比shift
短两个字符!)
我们的想法是我们将棋盘读成一个字符串(丢掉字母之间的额外空格),并记下它的宽度(通过计算字符直到第一个换行符)。然后我们使用s
正则表达式修饰符进行一系列正则表达式匹配以查找单词,以允许匹配跨越行。如果一个4字母宽的棋盘(所以每行5个字符包括换行符)和搜索词“CAR”,我们可以使模式/CAR/
匹配向前,/C...A...R/
以匹配向西南方向, /C....A....R/
匹配向下,/C.....A.....R/
匹配向东南方向匹配。对于每场比赛,我们记录比赛的开始和结束位置。
然后我们反转搜索词(“CAR” - >“RAC”)并再次执行,这样我们就可以匹配左,上,西北和东北的单词。当然,我们希望确保交换开始/结束位置。为了保存代码,我将匹配位置交换两次;前进单词的匹配被交换两次(因此它们是未交换的),而后向单词的匹配只交换一次,所以它们将被交换掉。
最后,只需将匹配偏移量转换为电路板字符串并将其转换为行/列对,并将输出格式化为问题所需的格式。
答案 3 :(得分:4)
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)
我第一次尝试打高尔夫球。
#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
(?字符)时,使用布尔值为1
或int
的事实。
示例:代替(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)
我猜还有一些改进空间,所有评论都欢迎。
策略:查找第一个字母的所有出现,然后尝试在所有方向上获取该单词。
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列