Word Search Puzzle

29

Dado um texto retangular como um quebra-cabeça de pesquisa por palavra e uma sequência de pesquisa, determine se o texto contém a sequência de pesquisa. A cadeia de pesquisa pode aparecer:

  • horizontal, vertical ou diagonal
  • para frente ou para trás

Você pode escrever uma função ou um programa e usar duas strings como entrada via argumento da função, ARGV ou STDIN. A saída deve ser um resultado verdadeiro ou falso que pode ser retornado da função ou gravado em STDOUT.

Suponha que o texto contenha caracteres ASCII imprimíveis arbitrários (códigos hexadecimais 20 a 7E) e caracteres de quebra de linha. As letras diferenciam maiúsculas de minúsculas. Você pode assumir que o texto de entrada é retangular, ou seja, todas as linhas têm o mesmo comprimento. Você pode decidir se a entrada termina com uma nova linha à direita ou não (se for importante para o envio).

Isso é código de golfe, a resposta mais curta (em bytes) vence.

Exemplos

Usando essa grade do artigo da Wikipedia sobre pesquisas de palavras como a primeira entrada:

WVERTICALL
ROOAFFLSAB
ACRILIATOA
NDODKONWDC
DRKESOODDK
OEEPZEGLIW
MSIIHOAERA
ALRKRRIRER
KODIDEDRCD
HELWSLEUTH

as seguintes cadeias de pesquisa devem produzir resultados verdadeiros ou falsos, respectivamente:

Truthy: RANDOM, VERTICAL, HORIZONTAL, WORDSEARCH, WIKIPEDIA, TAIL
Falsy:  WordSearch, CODEGOLF, UNICORN

Como alternativa, usando este texto de entrada

Lorem ipsum dolor sit amet consectetu
r adipisicing elit sed do eiusmod tem
por incididunt ut labore et dolore ma
gna aliqua. Ut enim ad minim veniam, 
quis nostrud exercitation ullamco lab
oris nisi ut aliquip ex ea commodo co
nsequat. Duis aute irure dolor in rep
rehenderit in voluptate velit esse ci
llum dolore eu fugiat nulla pariatur.

Obtemos os seguintes resultados de pesquisa (usando aspas agora, porque há espaços em algumas cadeias de pesquisa):

Truthy: "Lorem", "mine", "uma bop", "tuetdod", "snol,a", "texas", "pii.d  v", "vexta"
Falsy:  "lorem", "wordsearch", "pii.d v", "mute"
Martin Ender
fonte

Respostas:

7

CJam, 46 37 bytes

qN%{_zW%__,N**2$2$+,)/z\}4*]:+N*eas#)

Lê a grade de STDIN e a palavra como um argumento da linha de comandos. Imprime números inteiros positivos para correspondências e 0 para não correspondências.

Com o custo de dois bytes extras, as duas strings (palavra, avanço de linha, grade) podem ser lidas em STDIN:

qN%(\{_zW%__,N**2$2$+,)/z\}4*](\:+N*\#)

Você pode experimentar esta versão online com o intérprete CJam .

Exemplo de execução

$ for W in Lorem mine uma\ bop tuetdod snol,a texas pii.d\ \ v vexta WordSearch CODEGOLF UNICORN; do echo -e "$(cjam wordsearch.cjam "$W" < grid)\t$W"; done
1       Lorem
3085    mine
2055    uma bop
5142    tuetdod
3878    snol,a
1426    texas
5371    pii.d  v
2536    vexta
0       WordSearch
0       CODEGOLF
0       UNICORN

fundo

Suponha que a entrada tenha a seguinte grade:

ABCD
EFGH
IJKL

Dividindo em feeds de linha, obtemos a seguinte matriz:

A := [
         "ABCD"
         "EFGH"
         "IJKL"
     ]

Isso abrange as palavras do leste (palavras que vão da esquerda para a direita).

Agora, juntamos os elementos do Auso de uma sequência de len(A)feeds de linha como separador:

"ABCD⏎⏎⏎EFGH⏎⏎⏎IJKL"

Em seguida, cortamos a sequência resultante em pedaços de comprimento len(A) + len(A[0]) + 1:

[
    "ABCD⏎⏎⏎E"
    "FGH⏎⏎⏎IJ"
    "KL"
]

Se "compactar" a matriz (transpor linhas e colunas), obteremos:

[
    "AFK"
    "BGL"
    "CH"
    "D⏎"
    "⏎⏎"
    "⏎⏎"
    "I⏎"
    "EJ"
]

Isso abrange as palavras do sudeste.

Se compactarmos A e invertermos a ordem das linhas do resultado, obteremos:

[
    "DHL"
    "CGK"
    "BFJ"
    "AEI"
]

Isso abrange o Sul e - depois de repetir o processo para diagonais - as palavras do Sudoeste.

Fechando e revertendo novamente, obtemos:

[
    "LKJI"
    "HGFE"
    "DCBA"
]

Isso abrange West e - depois de repetir o processo para diagonais - palavras do noroeste.

Fechando e revertendo mais uma vez, obtemos:

[
    "IEA"
    "JFB"
    "KGC"
    "LHD"
]

Isso abrange Norte e - depois de repetir o processo para diagonais - palavras do Nordeste.

Como funciona

O código é como explicado na seção anterior, com duas pequenas diferenças:

  • Ele fecha e reverte uma vez no início.
  • Ele calcula len(A) + len(A[0])como len(A + zip(A)).

Por fim, junta todas as linhas de todas as matrizes geradas usando feeds de linha como separadores e procura a palavra na sequência resultante.

qN%                                   " A := split(input(),'\n')                          ";
   {                    }4*           " Do 4 times:                                       ";
    _zW%                              "   B := reverse(zip(A))                            ";
        __,N**                        "   C := B.join(len(B) * '\n')                      ";
              2$2$+,)/z               "   D := zip(C.chunks(len(A + B) + 1))              ";
                       \              "   A := B                                          ";
                           ]          " Collect all values of A and D in an array R.      ";
                            :+        " R := flatten(R)                                   ";
                              N*      " R := R.join('\n')                                 ";
                                eas   " I := flatten(ARGV)                                ";
                                   #) " print R.index(I) + 1                              ";
Dennis
fonte
7

Java: 183 211 321

boolean s(char[]w,char[]s){int j,z,a=s.length,i=a*9,f=1,q=0;for(;s[q++]>10;);for(;i-->0;)for(j=w.length,z=i/9;i%9!=4&j-->0&z>=0&z<a&&s[z]==w[j];z+=q*(i/3%3)+i%3-q-1)f*=j;return f==0;}

Uma força bruta básica. Não há muito mais a dizer, eu acho. A entrada é a agulha primeiro e o palheiro, o segundo. Supõe que a grade é finalizada com nova linha .

Uma versão um pouco mais legível com o caso de teste mostrado:

public class WordSearch {
    static String grid = "WVERTICALL\nROOAFFLSAB\nACRILIATOA\nNDODKONWDC\nDRKESOODDK\nOEEPZEGLIW\nMSIIHOAERA\nALRKRRIRER\nKODIDEDRCD\nHELWSLEUTH";
    static String search = "RANDOM";

    public static void main(String[] args) {
        System.out.println(new WordSearch().s(search.toCharArray(),grid.toCharArray()));
    }

    boolean s(char[]w,char[]s){
        int j,z,a=s.length,i=a*9,f=1,q=0;
        for(;s[q++]>10;);
        for(;i-->0;)
            for(j=w.length,z=i/9;
                i%9!=4&j-->0&z>=0&z<a&&s[z]==w[j];
                z+=q*(i/3%3)+i%3-q-1)
                f*=j;
        return f==0;
    }
}
Geobits
fonte
if(e<1)return 1>0;poderia ser return e<1;não poderia?
FryAmTheEggman
@FryAmTheEggman Não, isso retornaria depois de encontrar a primeira falha, para não pesquisar em toda a grade.
Geobits
11
Desculpe, me perdi um pouco lá; _;
FryAmTheEggman 18/09/14
4
O fora de dois para loops poderia ser recolhido em um lugar assim que você faria i=a*9,e for(;i-->0;)e z=i/9;e i%a!=4&e assim por diante?
Will
11
Uau, isso é tão parecido com o meu. E só dei uma olhada depois que eu já tinha começado. Não demorei para ver como funciona. +1.
Level River St
6

JavaScript (E6) 111 116

Pesquisa de força bruta para todos os personagens em todas as direções - o mais golfe possível

F=(b,w)=>
  [1,-1,r=b.search('\n'),-r,++r,-r,++r,-r].some(d=>
    [...b].some((_,p)=>
      [...w].every(c=>c==b[p+=d],p-=d)
    )
  )

Teste no console do FireFox / Firebug

;["RANDOM", "VERTICAL", "HORIZONTAL", "WORDSEARCH", "WIKIPEDIA", "TAIL",
"WordSearch", "CODEGOLF", "UNICORN"]
.forEach(w=>console.log('\n'+ w +' -> '+
  F("WVERTICALL\nROOAFFLSAB\nACRILIATOA\nNDODKONWDC\nDRKESOODDK\nOEEPZEGLIW\nMSIIHOAERA\nALRKRRIRER\nKODIDEDRCD\nHELWSLEUTH",w)))

Saída

RANDOM -> true
VERTICAL -> true
HORIZONTAL -> true
WORDSEARCH -> true
WIKIPEDIA -> true
TAIL -> true
WordSearch -> false
CODEGOLF -> false
UNICORN -> false
edc65
fonte
5

Python, 175

Não é muito inspirado, mas aqui vai:

def s(h,n):
 l=h.find('\n')+2;h+='\n'*l;L=i=len(h)
 while i>0:
  i-=1
  for d in[-l,1-l,2-l,-1,1,l-2,l-1,l]:
    j=i;m=len(n)
    for c in n:m-=c==h[j%L];j+=d
    if m<1:i=-1
 return-i

O primeiro argumento é palheiro, o segundo é agulha.

Ell
fonte
Eu acho que você pode salvar 6 caracteres usando h,n=input()e print. Além disso, isso funciona com entradas não quadradas? (? m = len (n) eu admitir que não compreender totalmente o que está fazendo, então eu poderia estar completamente errado!)
FryAmTheEggman
@FryAmTheEggman: Sim, funciona com entradas não quadradas.
Ell
11
Algumas otimizações padrão do Python: while i>0para while i:(já ique nunca podem se tornar negativas), if m<1:i=-1para i-=m<1.
xnor
11
@ xnor Acho que você pode ter interpretado mal if m<1:i=-1, if m<1:i-=1pois nenhum deles funcionará porque ele está se preparando ipara ser negativo.
FryAmTheEggman 18/09/14
@FryAmTheEggman Ah, sim, eu interpretei totalmente isso errado.
xnor
5

Bash + coreutils, 214 169 bytes

r()(tee >(rev) $@)
t()(eval paste -d'"\0"' `sed 's/.*/<(fold -1<<<"&")/'`)
d()(while IFS= read l;do echo "$a$l";a+=_;done|t)
r<<<"$2"|r >(d) >(r|t) >(r|d)|r|grep -q "$1"

Utiliza 3 funções de transformação e r, para reverter, transpor e deslocamento diagonal, em todas as combinações necessárias.td

Atualização - a rfunção agora produz saída invertida e não invertida para maior golficidade

Entrada via argumentos da linha de comando - cadeia de pesquisa, seguida pelo bloco de pesquisa de palavras retangular (separado por nova linha).

A saída é um código de status de saída do shell correto para o idioma - 0 significa VERDADEIRO e 1 significa FALSO.

Saída:

$ for w in "Lorem" "mine" "uma bop" "tuetdod" "snol,a" "texas" "pii.d  v" "vexta" ; do ./ws.sh "$w" "Lorem ipsum dolor sit amet consectetu
r adipisicing elit sed do eiusmod tem
por incididunt ut labore et dolore ma
gna aliqua. Ut enim ad minim veniam, 
quis nostrud exercitation ullamco lab
oris nisi ut aliquip ex ea commodo co
nsequat. Duis aute irure dolor in rep
rehenderit in voluptate velit esse ci
llum dolore eu fugiat nulla pariatur."; echo $?; done
0
0
0
0
0
0
0
0
$ for w in WordSearch CODEGOLF UNICORN ; do ./ws.sh "$w" "Lorem ipsum dolor sit amet consectetu
r adipisicing elit sed do eiusmod tem
por incididunt ut labore et dolore ma
gna aliqua. Ut enim ad minim veniam, 
quis nostrud exercitation ullamco lab
oris nisi ut aliquip ex ea commodo co
nsequat. Duis aute irure dolor in rep
rehenderit in voluptate velit esse ci
llum dolore eu fugiat nulla pariatur."; echo $?; done
1
1
1
$ 
Trauma Digital
fonte
1. Eu estava prestes a sugerir T()(tee >(r) $@), mas isso é ainda melhor. 2. Acho que nunca vi essa sintaxe de função antes. 3. Considerando cadeias não vazias verdadeiras e cadeias vazias falsas, acho que você pode omitir -q.
Dennis
Se você definir r()(tee >(rev) $@), r<<<"$2"|r >(d) >(r|t) >(r|d)|r|grep "$1"deve funcionar também.
Dennis
Não testei mais nada, mas os dois casos de teste da pergunta foram retirados quando tentei.
Dennis
@ Dennis Nice - sim, funciona agora. Eu verifiquei com Martin - ele quer -qque permaneça.
Digital Trauma
5

C, 163

f(char*h,char*n){int i,j,d,p,y=0,l=strlen(h),w=strchr(h,10)-h+1;for(i=l*9;i--;y+=d&&!n[j]){p=i/9;d=i%9/3*w-w+i%3-1;for(j=0;p>=0&p<l&h[p]==n[j];j++)p+=d;}return y;}

Sem rearranjo da grade, eu simplesmente tento todas as letras iniciais em todas as direções e ando até que eu corra para fora da grade ou encontre uma incompatibilidade.

Aproveito o fato de uma string C terminar em um byte zero. Como não há zero bytes na grade, SEMPRE haverá uma incompatibilidade. Mas se a incompatibilidade ocorrer no byte zero, sabemos que encontramos o final da string a ser pesquisada e a registramos como uma correspondência.

Ungolfed em um programa de teste

char h[]="WVERTICALL\nROOAFFLSAB\nACRILIATOA\nNDODKONWDC\nDRKESOODDK\nOEEPZEGLIW\nMSIIHOAERA\nALRKRRIRER\nKODIDEDRCD\nHELWSLEUTH\n";

f(char*h,char*n){                                   //haystack,needle
  int i,j,d,p,y=0,l=strlen(h),w=strchr(h,10)-h+1;   //l=length of whole grid. w=width of row, including terminal newline ASCII 10
  for(i=l*9;i--;){                                  //for each start letter and direction
    p=i/9;                                          //pointer to start letter
    d=i%9/3*w-w+i%3-1;                              //9 possible values of direction vector {-w,0,w}+{-1,0,1}
    for(j=0;p>=0&p<l&h[p]==n[j];j++)p+=d;           //walk p in the direction defined by d until we walk off the top or bottom of the grid or a mismatch is fount
    y+=d&&!n[j];                                    //if we got all the way to the terminal 0, record it as a hit. If d=0, don't record as this is an invalid direction.
  }
  return y;   
}

main(int c, char**v){
  printf("%d",f(h,v[1]));  
}

Saída

Observe que a função retornará o número total de incidências da string pesquisada na grade. Assim, para ODele retorna 6. Se nenhuma ocorrência for encontrada, ele retornará 0, que é o único valor falso em C. Alterar para y|=d*!n[j]salvaria um caractere, mas perderia essa funcionalidade.

$ ./a UNICORN
0

$ ./a CODEGOLF
0

$ ./a WordSearch
0

$ ./a RANDOM
1

$ ./a WORDSEARCH
1

$ ./a VERTICAL
1

$ ./a HORIZONTAL
1

$ ./a WIKIPEDIA
1

$ ./a TAIL
1

$ ./a OD
6
Level River St
fonte
5

C # - 218 197 186 bytes

Função C # que usa 2 strings, a primeira a procurar, mais tarde a grade com linhas ( \n) entre linhas. As coisas estão ficando desesperadas agora ... tão desesperadas que minha edição anterior não funcionou!

Código de golfe:

bool F(string D,string S){int l=S.Length,i=l*13,r,p;for(S+="\n";i-->l*5;i=r<0?r:i)for(r=D.Length,p=i%l;p>-1&p<l&r-->0&&D[r]==S[p];p+=(S.IndexOf('\n')+1)*(i/l%9/3-1)+i/l%3-1);return i<0;}

Menos golfe com o código de teste:

class P
{
    static void Main()
    {
        System.Console.WriteLine(new P().F(System.Console.ReadLine(),System.Console.In.ReadToEnd())?"Truthy":"Falsy"); // because why not
    }

    bool F(string D,string S)
    {
        int l=S.Length,i=l*13,r,p;

        for(S+="\n";i-->l*5;i=r<0?r:i) // for each cell/direction
            for(r=D.Length,p=i%l;p>-1&p<l&r-->0&&D[r]==S[p];p+=(S.IndexOf('\n')+1)*(i/l%9/3-1)+i/l%3-1); // test against string (backwards)

        return i<0;
    }
}
VisualMelon
fonte
4

Haskell - 173

Em vez de pesquisar diretamente na grade, eu a transformo de maneiras diferentes e associo a palavra a cada linha da nova grade.

Por exemplo,

G1    G2    G3       G4   G5

abcd  aA1   abcd     a..  ..1
ABCD  bB2   .ABCD    bA.  .A2
1234  cC3   ..1234   cB1  aB3
      dD4            dC2  bC4
                      D3  cD
                       4  d

Pesquise a palavra em cada linha de G1, G2, G4 e G5, e pronto. Note que o G3 não é usado, eu posto aqui apenas para ilustração.

Uma idéia semelhante é aplicada para pesquisar para frente e para trás: basta pesquisar a palavra original e a palavra invertida.

Então, agora pesquisamos 8 direções. Aqui está o código, cuja correção foi verificada por outro script .

import Data.List
v=reverse
t=transpose
y=any
d r=zipWith(++)(scanr(\_->('\n':))[]r)r
g r w=y(y$y((==w).take(length w)).tails)[r,t r,t.d$r,t.d.v$r]
f r w=y(g(lines r))[w,v w]

A função fé o que queremos e seu argumento ré a string do retângulo, wé a palavra a ser pesquisada.

Raio
fonte
4

Python 2 - 246 259 275 308 298 297 294 313 322

w,s=input()
r=range
d='\n'
I=''.join
w=w.split(d)
t,u=len(w),len(w[0])
v=d.join([I(x)for x in zip(*w)]+[d]+[I([w[i+j][i]for i in r(min(u,t-j))])+d+I([w[i][i+j]for i in r(min(t,u-j))])for j in r(max(t,u))]+[d]+w)
print s in v or s[::-1]in v

Agradecemos a Will por alguma ajuda para lidar com a impressão e a definição da junção.

Graças à estrada de ferro subterrânea por me lembrar dos espaços de golfe corretamente; p

Corrigido para partidas ruins devido ao uso de ',' como delimitador.

Aparentemente, a melhor maneira de jogar golfe é adicionar toneladas de rolagem horizontal.

Entrada como espaços em branco estrondo nova linha delimitada linhas entre aspas: "WVERTICALL \ nROOAFFLSAB \ nACRILIATOA \ nNDODKONWDC \ nDRKESOODDK \ nOEEPZEGLIW \ nMSIIHOAERA \ nALRKRRIRER \ nKODIDEDRCD \ nHELWSLEUTH", "aleatório"

FryAmTheEggman
fonte
11
L=len;J=''.joinetc e print any(s in(v,d,w,r...))? Eu estava indo no mesmo sentido quando vi você postou :)
Will
@ Will Obrigado pela ajuda! A definição de custos de len apenas o número de caracteres que ele salva, e eu não tenho certeza sobre como definir a junção da melhor maneira possível (alguns têm vírgulas), então farei isso daqui a pouco.
FryAmTheEggman 18/09/14
Em qualquer lugar que você tenha )ou tenha ]seguido um espaço, você poderá removê-lo.
Undergroundmonorail
2

APL (Dyalog Classic) , 44 bytes

1∊⍞⍷↑{⍉0,⍵,↑(0,⊢)\↓0,⍵}¨{⍉⌽⍵}\4⍴⊂↑a⊆⍨a≠⊃⌽a←⎕

Experimente online!

ngn
fonte
Hum, desculpe, mas parece que você não pode obter informações como essa aqui, ela precisa ser \nseparada (ou seja, ter ⎕TC[2]como separador).
Erik o Outgolfer
@EriktheOutgolfer oh merda ... eu vou consertar isso mais tarde. Obrigado.
NGN
corrigido agora, infelizmente, por muito mais tempo
ngn
0

J , 60 53 bytes

<@[e.[:,[:(;|.)@>[:<\\.@>[:(<"1,</.)@>@(;|.@|:)[;.2@]

Experimente online!

Requer a primeira entrada para não conter novas linhas.

Explicação:

linkrotate=: ;|.@|:     NB. link with itself rotated 90° ccw
infixes   =: <\\.       NB. list of boxes containing the infixes
lines     =: <"1 , </.  NB. horizontal and diagonal lines, boxed
linkrev   =: ;|.        NB. link with itself reversed
appearin  =: <@[ e. [: , [: linkrev@> [: infixes@> [: lines@>@linkrotate [;.2@]

Experimente online!

Ganchos são úteis.

user202729
fonte
Parece que isso também funciona. (51 bytes)
user202729
0

Gelatina , 16 bytes

Resolvido um desafio relacionado (possivelmente duplicado) com 15 desses 16 bytes como o núcleo do código ...

ỴZU$3С;ŒD$€Ẏw€Ẹ

Um link diádico que aceita uma lista de caracteres à esquerda e uma lista de caracteres à direita que retorna 1 se encontrado e 0 se não.

Experimente online!

Quão?

ZU$3С;ŒD$€Ẏw€Ẹ - Link: words, grid
   3С          - repeat three times and collect the results (inc input):
  $             -   last two links as a monad:
Z               -     transpose
 U              -     upend     (together these rotate by a quarter)
          €     - for €ach:
         $      -   last two links as a monad:
       ŒD       -     get forward-diagonals
      ;         -     concatenate
           Ẏ    - tighten (to get all the runs across the grid) 
             €  - for €ach run:
            w   -   sublist-index (0 if not found)
              Ẹ - any truthy? (i.e. was the word found?)
Jonathan Allan
fonte