Подтвердить что ты не робот

Code Golf: решение поиска слов

Примечание. Это моя первая проблема/вопрос в Code Golf, поэтому я, возможно, не буду использовать правильный формат ниже. Я не уверен, как отметить этот конкретный вопрос, и должно ли это быть вики сообщества? Спасибо!

Этот вызов Code Golf предназначен для решения поисков слов!

Поиск по словам, как определено в Википедии, есть:

Поиск слов, поиск слов, поиск слов, слово сыщик или загадочное слово головоломка слово игра, которая является буквами слова в сетке, которая обычно имеет прямоугольной или квадратной формы. Цель этой головоломки - найти и отметьте все слова, скрытые внутри коробка. Слова могут быть горизонтально, вертикально или по диагонали. Часто список скрытых слова предоставляются, но больше сложные головоломки могут позволить игроку выяснить их. Много слова поиска у головоломок есть тема, в которой все скрытые слова связаны.

Слово ищет этот вызов будет прямоугольными сетками со списком слов для поиска. Слова могут быть написаны по вертикали, по горизонтали или по диагонали.


Input/Output

Пользователь вводит свой поиск слов, а затем вводит слово, которое можно найти в их сетке. Эти два входа передаются функции, которую вы будете писать. Это зависит от вас, как вы хотите объявлять и обрабатывать эти объекты.

Используя описанную ниже стратегию или свою собственную, функция находит конкретное слово в поиске и выводит свои начальные координаты (просто номер строки и номер столбца) и конечные координаты. Если вы обнаружите два вхождения слова, вы должны вывести оба набора координат. Если слово является палиндром, вы можете произвольно выбрать один конец как "начало" слова.


Пример

Input:

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

Стратегии

Вот несколько стратегий, которые вы можете использовать. Вам решать, какую стратегию вы хотите использовать; он не должен быть в этом списке.

  • Ищем первую букву слова; в каждом случае, глядя на восемь окружающих букв, чтобы увидеть, есть ли следующая буква слова.
  • То же, что и выше, за исключением того, что вы ищете часть слова, которое имеет две одинаковые буквы бок о бок.
  • Подсчитайте, как часто каждая буква алфавита присутствует во всей сетке, затем выберите одну из наименее известных букв из слова, которое вы должны найти и найти письмо. В каждом случае буквы вы смотрите на восемь своих букв, чтобы увидеть, есть ли следующая и предыдущая буквы этого слова.
4b9b3361

Ответ 1

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")

Ответ 2

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,[email protected]/$.,$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

Ответ 3

Perl - 243

(Не считая строк, все из которых являются необязательными)

В большинстве случаев код для игры в гольф можно найти здесь.

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

Использование: выполняется как script. Либо wordsearch.pl boardfile searchword для чтения из файла, либо wordsearch.pl searchword для чтения платы с STDIN (эй, pop на два символа короче shift!)

Идея состоит в том, что мы читаем плату в строку (отбрасывая лишние пробелы между буквами), а также учитываем, насколько она широка (путем подсчета символов до первой новой строки). Затем мы выполняем серию регулярных совпадений, чтобы найти слово, используя модификатор s regex, чтобы позволить совпадению охватывать линии. Учитывая, что доска шириной 4 буквы (каждая строка состоит из 5 символов, включая новую строку), а слово поиска "CAR", мы можем сделать шаблоны /CAR/ для соответствия вперед, /C...A...R/, чтобы соответствовать направлению на юго-запад, /C....A....R/ до совпадение идет вниз, а /C.....A.....R/ - на юго-восток. Для каждого матча мы записываем начальную и конечную позиции матча.

Затем мы разворачиваем слово поиска ( "CAR" → "RAC" ) и делаем это снова, что позволяет нам сопоставлять слова, идущие влево, вверх, на северо-запад и северо-восток. Конечно, мы хотим убедиться, что начальная и конечная позиции также заменены. Чтобы сохранить код, я дважды меняю позиции совпадения; совпадения для форвардного слова меняются местами раз в два раза (так что они выходят без перестановки), в то время как совпадения для обратного слова заменяются только один раз, поэтому они будут заменены.

Наконец, это просто вопрос смещения смещения в строку доски и превращение их в пары строк/столбцов и форматирование вывода, как проблема этого хочет.

Ответ 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

Ответ 5

С++ 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;}

Он компилируется без предупреждений на gcc без дополнительных флагов.

Здесь версия с пробелом:

#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 char).
    Пример: вместо if(x)printf(""); напишите x?printf(""):0;. Это работает, потому что printf возвращает int.

  • Используйте тот факт, что booleans 0 или 1 при использовании в качестве int (? chars).
    Пример: вместо (y>0?r-l:r) напишите r-(y>0)*l. Экономия здесь находится в круглых скобках, которые были необходимы в этой ситуации.

    Циклы
  • while никогда не короче циклов for и больше времени ( >= 0 символов).
    Пример: while(x)y; до тех пор, пока for(;x;y);, но с for вы также получите тело цикла, не оплачивая дополнительный ;.

  • Поместите ваши приращения цикла в последнее выражение, которое использует счетчик циклов (1 char).
    Пример: вместо for(;x<b;++x)printf("%i",x); напишите for(;x<b;)printf("%i",x++);.

  • Оставьте main возвращаемый тип (4 символа).

  • Оставьте команду main return (9 символов).

  • Используйте & и | вместо && и ||, когда это возможно (1 char).
    Пример: вместо if(x||y) напишите if(x|y). Это работает только в том случае, если вы не зависите от поведения короткого замыкания && и ||.

  • Вставьте функцию strlen и удалите #include<string.h> (11 символов).

Если вам не нравятся предупреждения компилятора:

  • Не включайте заголовки (много символов).

Ответ 6

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

Выпущено в соответствии с лицензией "edit-the-answer-вместо-commenting-on-how-I-should-fix-this".

Ответ 7

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 → строка 5, столбец 1